LCOV - code coverage report
Current view: top level - source3/smbd - share_access.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 89 112 79.5 %
Date: 2024-04-13 12:30:31 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Check access based on valid users, read list and friends
       4             :    Copyright (C) Volker Lendecke 2005
       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 "smbd/smbd.h"
      22             : #include "smbd/globals.h"
      23             : #include "../libcli/security/security.h"
      24             : #include "passdb/lookup_sid.h"
      25             : #include "auth.h"
      26             : #include "source3/lib/substitute.h"
      27             : 
      28             : /*
      29             :  * No prefix means direct username
      30             :  * @name means netgroup first, then unix group
      31             :  * &name means netgroup
      32             :  * +name means unix group
      33             :  * + and & may be combined
      34             :  */
      35             : 
      36         446 : static bool do_group_checks(const char **name, const char **pattern)
      37             : {
      38         446 :         if ((*name)[0] == '@') {
      39          18 :                 *pattern = "&+";
      40          18 :                 *name += 1;
      41          18 :                 return True;
      42             :         }
      43             : 
      44         428 :         if (((*name)[0] == '+') && ((*name)[1] == '&')) {
      45          12 :                 *pattern = "+&";
      46          12 :                 *name += 2;
      47          12 :                 return True;
      48             :         }
      49             : 
      50         416 :         if ((*name)[0] == '+') {
      51          24 :                 *pattern = "+";
      52          24 :                 *name += 1;
      53          24 :                 return True;
      54             :         }
      55             : 
      56         392 :         if (((*name)[0] == '&') && ((*name)[1] == '+')) {
      57          12 :                 *pattern = "&+";
      58          12 :                 *name += 2;
      59          12 :                 return True;
      60             :         }
      61             : 
      62         380 :         if ((*name)[0] == '&') {
      63           4 :                 *pattern = "&";
      64           4 :                 *name += 1;
      65           4 :                 return True;
      66             :         }
      67             : 
      68         376 :         return False;
      69             : }
      70             : 
      71         446 : static bool token_contains_name(TALLOC_CTX *mem_ctx,
      72             :                                 const char *username,
      73             :                                 const char *domain,
      74             :                                 const char *sharename,
      75             :                                 const struct security_token *token,
      76             :                                 const char *name)
      77             : {
      78           0 :         const char *prefix;
      79           0 :         struct dom_sid sid;
      80           0 :         enum lsa_SidType type;
      81             : 
      82         446 :         if (username != NULL) {
      83         446 :                 size_t domain_len = domain != NULL ? strlen(domain) : 0;
      84             : 
      85             :                 /* Check if username starts with domain name */
      86         446 :                 if (domain_len > 0) {
      87         446 :                         const char *sep = lp_winbind_separator();
      88         446 :                         int cmp = strncasecmp_m(username, domain, domain_len);
      89         446 :                         if (cmp == 0 && sep[0] == username[domain_len]) {
      90             :                                 /* Move after the winbind separator */
      91         156 :                                 domain_len += 1;
      92             :                         } else {
      93         290 :                                 domain_len = 0;
      94             :                         }
      95             :                 }
      96         446 :                 name = talloc_sub_basic(mem_ctx,
      97             :                                         username + domain_len,
      98             :                                         domain,
      99             :                                         name);
     100             :         }
     101         446 :         if (sharename != NULL) {
     102         350 :                 name = talloc_string_sub(mem_ctx, name, "%S", sharename);
     103             :         }
     104             : 
     105         446 :         if (name == NULL) {
     106             :                 /* This is too security sensitive, better panic than return a
     107             :                  * result that might be interpreted in a wrong way. */
     108           0 :                 smb_panic("substitutions failed");
     109             :         }
     110             : 
     111         446 :         if ( string_to_sid( &sid, name ) ) {
     112           0 :                 DEBUG(5,("token_contains_name: Checking for SID [%s] in token\n", name));
     113           0 :                 return nt_token_check_sid( &sid, token );
     114             :         }
     115             : 
     116         446 :         if (!do_group_checks(&name, &prefix)) {
     117         376 :                 if (!lookup_name_smbconf(mem_ctx, name, LOOKUP_NAME_ALL,
     118             :                                  NULL, NULL, &sid, &type)) {
     119           0 :                         DEBUG(5, ("lookup_name %s failed\n", name));
     120           0 :                         return False;
     121             :                 }
     122         376 :                 if (type != SID_NAME_USER) {
     123           0 :                         DEBUG(5, ("%s is a %s, expected a user\n",
     124             :                                   name, sid_type_lookup(type)));
     125           0 :                         return False;
     126             :                 }
     127         376 :                 return nt_token_check_sid(&sid, token);
     128             :         }
     129             : 
     130         104 :         for (/* initialized above */ ; *prefix != '\0'; prefix++) {
     131         100 :                 if (*prefix == '+') {
     132          66 :                         if (!lookup_name_smbconf(mem_ctx, name,
     133             :                                          LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
     134             :                                          NULL, NULL, &sid, &type)) {
     135           0 :                                 DEBUG(5, ("lookup_name %s failed\n", name));
     136           0 :                                 return False;
     137             :                         }
     138          66 :                         if ((type != SID_NAME_DOM_GRP) &&
     139           0 :                             (type != SID_NAME_ALIAS) &&
     140           0 :                             (type != SID_NAME_WKN_GRP)) {
     141           0 :                                 DEBUG(5, ("%s is a %s, expected a group\n",
     142             :                                           name, sid_type_lookup(type)));
     143           0 :                                 return False;
     144             :                         }
     145          66 :                         if (nt_token_check_sid(&sid, token)) {
     146          66 :                                 return True;
     147             :                         }
     148           0 :                         continue;
     149             :                 }
     150          34 :                 if (*prefix == '&') {
     151          34 :                         if (username) {
     152          34 :                                 if (user_in_netgroup(mem_ctx, username, name)) {
     153           0 :                                         return True;
     154             :                                 }
     155             :                         }
     156          34 :                         continue;
     157             :                 }
     158           0 :                 smb_panic("got invalid prefix from do_groups_check");
     159             :         }
     160           4 :         return False;
     161             : }
     162             : 
     163             : /*
     164             :  * Check whether a user is contained in the list provided.
     165             :  *
     166             :  * Please note that the user name and share names passed in here mainly for
     167             :  * the substitution routines that expand the parameter values, the decision
     168             :  * whether a user is in the list is done after a lookup_name on the expanded
     169             :  * parameter value, solely based on comparing the SIDs in token.
     170             :  *
     171             :  * The other use is the netgroup check when using @group or &group.
     172             :  */
     173             : 
     174       48669 : bool token_contains_name_in_list(const char *username,
     175             :                                  const char *domain,
     176             :                                  const char *sharename,
     177             :                                  const struct security_token *token,
     178             :                                  const char **list)
     179             : {
     180       48669 :         if (list == NULL) {
     181       47452 :                 return False;
     182             :         }
     183         597 :         while (*list != NULL) {
     184         446 :                 TALLOC_CTX *frame = talloc_stackframe();
     185           0 :                 bool ret;
     186             : 
     187         446 :                 ret = token_contains_name(frame, username, domain, sharename,
     188             :                                           token, *list);
     189         446 :                 TALLOC_FREE(frame);
     190         446 :                 if (ret) {
     191         283 :                         return true;
     192             :                 }
     193         163 :                 list += 1;
     194             :         }
     195         151 :         return False;
     196             : }
     197             : 
     198             : /*
     199             :  * Check whether the user described by "token" has access to share snum.
     200             :  *
     201             :  * This looks at "invalid users" and "valid users".
     202             :  *
     203             :  * Please note that the user name and share names passed in here mainly for
     204             :  * the substitution routines that expand the parameter values, the decision
     205             :  * whether a user is in the list is done after a lookup_name on the expanded
     206             :  * parameter value, solely based on comparing the SIDs in token.
     207             :  *
     208             :  * The other use is the netgroup check when using @group or &group.
     209             :  */
     210             : 
     211      143944 : bool user_ok_token(const char *username, const char *domain,
     212             :                    const struct security_token *token, int snum)
     213             : {
     214        2299 :         const struct loadparm_substitution *lp_sub =
     215      143944 :                 loadparm_s3_global_substitution();
     216             : 
     217      143944 :         if (lp_invalid_users(snum) != NULL) {
     218          64 :                 if (token_contains_name_in_list(username, domain,
     219          32 :                                                 lp_servicename(talloc_tos(), lp_sub, snum),
     220             :                                                 token,
     221             :                                                 lp_invalid_users(snum))) {
     222           8 :                         DEBUG(10, ("User %s in 'invalid users'\n", username));
     223           8 :                         return False;
     224             :                 }
     225             :         }
     226             : 
     227      143936 :         if (lp_valid_users(snum) != NULL) {
     228         564 :                 if (!token_contains_name_in_list(username, domain,
     229         282 :                                                  lp_servicename(talloc_tos(), lp_sub, snum),
     230             :                                                  token,
     231             :                                                  lp_valid_users(snum))) {
     232         119 :                         DEBUG(10, ("User %s not in 'valid users'\n",
     233             :                                    username));
     234         119 :                         return False;
     235             :                 }
     236             :         }
     237             : 
     238      143817 :         DEBUG(10, ("user_ok_token: share %s is ok for unix user %s\n",
     239             :                    lp_servicename(talloc_tos(), lp_sub, snum), username));
     240             : 
     241      141518 :         return True;
     242             : }
     243             : 
     244             : /*
     245             :  * Check whether the user described by "token" is restricted to read-only
     246             :  * access on share snum.
     247             :  *
     248             :  * This looks at "read list", "write list" and "read only".
     249             :  *
     250             :  * Please note that the user name and share names passed in here mainly for
     251             :  * the substitution routines that expand the parameter values, the decision
     252             :  * whether a user is in the list is done after a lookup_name on the expanded
     253             :  * parameter value, solely based on comparing the SIDs in token.
     254             :  *
     255             :  * The other use is the netgroup check when using @group or &group.
     256             :  */
     257             : 
     258       96392 : bool is_share_read_only_for_token(const char *username,
     259             :                                   const char *domain,
     260             :                                   const struct security_token *token,
     261             :                                   connection_struct *conn)
     262             : {
     263        1542 :         const struct loadparm_substitution *lp_sub =
     264       96392 :                 loadparm_s3_global_substitution();
     265       96392 :         int snum = SNUM(conn);
     266       96392 :         bool result = conn->read_only;
     267             : 
     268       96392 :         if (lp_read_list(snum) != NULL) {
     269           0 :                 if (token_contains_name_in_list(username, domain,
     270           0 :                                                 lp_servicename(talloc_tos(), lp_sub, snum),
     271             :                                                 token,
     272             :                                                 lp_read_list(snum))) {
     273           0 :                         result = True;
     274             :                 }
     275             :         }
     276             : 
     277       96392 :         if (lp_write_list(snum) != NULL) {
     278          48 :                 if (token_contains_name_in_list(username, domain,
     279          24 :                                                 lp_servicename(talloc_tos(), lp_sub, snum),
     280             :                                                 token,
     281             :                                                 lp_write_list(snum))) {
     282          24 :                         result = False;
     283             :                 }
     284             :         }
     285             : 
     286       96392 :         DEBUG(10,("is_share_read_only_for_user: share %s is %s for unix user "
     287             :                   "%s\n", lp_servicename(talloc_tos(), lp_sub, snum),
     288             :                   result ? "read-only" : "read-write", username));
     289             : 
     290       96392 :         return result;
     291             : }

Generated by: LCOV version 1.14