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 2 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, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21#include "includes.h" 22 23/* 24 * No prefix means direct username 25 * @name means netgroup first, then unix group 26 * &name means netgroup 27 * +name means unix group 28 * + and & may be combined 29 */ 30 31extern userdom_struct current_user_info; 32 33static BOOL do_group_checks(const char **name, const char **pattern) 34{ 35 if ((*name)[0] == '@') { 36 *pattern = "&+"; 37 *name += 1; 38 return True; 39 } 40 41 if (((*name)[0] == '+') && ((*name)[1] == '&')) { 42 *pattern = "+&"; 43 *name += 2; 44 return True; 45 } 46 47 if ((*name)[0] == '+') { 48 *pattern = "+"; 49 *name += 1; 50 return True; 51 } 52 53 if (((*name)[0] == '&') && ((*name)[1] == '+')) { 54 *pattern = "&+"; 55 *name += 2; 56 return True; 57 } 58 59 if ((*name)[0] == '&') { 60 *pattern = "&"; 61 *name += 1; 62 return True; 63 } 64 65 return False; 66} 67 68static BOOL token_contains_name(TALLOC_CTX *mem_ctx, 69 const char *username, 70 const char *sharename, 71 const struct nt_user_token *token, 72 const char *name) 73{ 74 const char *prefix; 75 DOM_SID sid; 76 enum lsa_SidType type; 77 78 if (username != NULL) { 79 name = talloc_sub_basic(mem_ctx, username, 80 current_user_info.domain, name); 81 } 82 if (sharename != NULL) { 83 name = talloc_string_sub(mem_ctx, name, "%S", sharename); 84 } 85 86 if (name == NULL) { 87 /* This is too security sensitive, better panic than return a 88 * result that might be interpreted in a wrong way. */ 89 smb_panic("substitutions failed\n"); 90 } 91 92 /* check to see is we already have a SID */ 93 94 if ( string_to_sid( &sid, name ) ) { 95 DEBUG(5,("token_contains_name: Checking for SID [%s] in token\n", name)); 96 return nt_token_check_sid( &sid, token ); 97 } 98 99 if (!do_group_checks(&name, &prefix)) { 100 if (!lookup_name_smbconf(mem_ctx, name, LOOKUP_NAME_ALL, 101 NULL, NULL, &sid, &type)) { 102 DEBUG(5, ("lookup_name %s failed\n", name)); 103 return False; 104 } 105 if (type != SID_NAME_USER) { 106 DEBUG(5, ("%s is a %s, expected a user\n", 107 name, sid_type_lookup(type))); 108 return False; 109 } 110 return nt_token_check_sid(&sid, token); 111 } 112 113 for (/* initialized above */ ; *prefix != '\0'; prefix++) { 114 if (*prefix == '+') { 115 if (!lookup_name_smbconf(mem_ctx, name, 116 LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP, 117 NULL, NULL, &sid, &type)) { 118 DEBUG(5, ("lookup_name %s failed\n", name)); 119 return False; 120 } 121 if ((type != SID_NAME_DOM_GRP) && 122 (type != SID_NAME_ALIAS) && 123 (type != SID_NAME_WKN_GRP)) { 124 DEBUG(5, ("%s is a %s, expected a group\n", 125 name, sid_type_lookup(type))); 126 return False; 127 } 128 if (nt_token_check_sid(&sid, token)) { 129 return True; 130 } 131 continue; 132 } 133 if (*prefix == '&') { 134 if (user_in_netgroup(username, name)) { 135 return True; 136 } 137 continue; 138 } 139 smb_panic("got invalid prefix from do_groups_check\n"); 140 } 141 return False; 142} 143 144/* 145 * Check whether a user is contained in the list provided. 146 * 147 * Please note that the user name and share names passed in here mainly for 148 * the substitution routines that expand the parameter values, the decision 149 * whether a user is in the list is done after a lookup_name on the expanded 150 * parameter value, solely based on comparing the SIDs in token. 151 * 152 * The other use is the netgroup check when using @group or &group. 153 */ 154 155BOOL token_contains_name_in_list(const char *username, 156 const char *sharename, 157 const struct nt_user_token *token, 158 const char **list) 159{ 160 TALLOC_CTX *mem_ctx; 161 162 if (list == NULL) { 163 return False; 164 } 165 166 if ( (mem_ctx = talloc_new(NULL)) == NULL ) { 167 smb_panic("talloc_new failed\n"); 168 } 169 170 while (*list != NULL) { 171 if (token_contains_name(mem_ctx, username, sharename,token, *list)) { 172 TALLOC_FREE(mem_ctx); 173 return True; 174 } 175 list += 1; 176 } 177 178 TALLOC_FREE(mem_ctx); 179 return False; 180} 181 182/* 183 * Check whether the user described by "token" has access to share snum. 184 * 185 * This looks at "invalid users", "valid users" and "only user/username" 186 * 187 * Please note that the user name and share names passed in here mainly for 188 * the substitution routines that expand the parameter values, the decision 189 * whether a user is in the list is done after a lookup_name on the expanded 190 * parameter value, solely based on comparing the SIDs in token. 191 * 192 * The other use is the netgroup check when using @group or &group. 193 */ 194 195BOOL user_ok_token(const char *username, struct nt_user_token *token, int snum) 196{ 197 if (lp_invalid_users(snum) != NULL) { 198 if (token_contains_name_in_list(username, lp_servicename(snum), 199 token, 200 lp_invalid_users(snum))) { 201 DEBUG(10, ("User %s in 'invalid users'\n", username)); 202 return False; 203 } 204 } 205 206 if (lp_valid_users(snum) != NULL) { 207 if (!token_contains_name_in_list(username, 208 lp_servicename(snum), token, 209 lp_valid_users(snum))) { 210 DEBUG(10, ("User %s not in 'valid users'\n", 211 username)); 212 return False; 213 } 214 } 215 216 if (lp_onlyuser(snum)) { 217 const char *list[2]; 218 list[0] = lp_username(snum); 219 list[1] = NULL; 220 if ((list[0] == NULL) || (*list[0] == '\0')) { 221 DEBUG(0, ("'only user = yes' and no 'username ='\n")); 222 return False; 223 } 224 if (!token_contains_name_in_list(NULL, lp_servicename(snum), 225 token, list)) { 226 DEBUG(10, ("%s != 'username'\n", username)); 227 return False; 228 } 229 } 230 231 DEBUG(10, ("user_ok_token: share %s is ok for unix user %s\n", 232 lp_servicename(snum), username)); 233 234 return True; 235} 236 237/* 238 * Check whether the user described by "token" is restricted to read-only 239 * access on share snum. 240 * 241 * This looks at "invalid users", "valid users" and "only user/username" 242 * 243 * Please note that the user name and share names passed in here mainly for 244 * the substitution routines that expand the parameter values, the decision 245 * whether a user is in the list is done after a lookup_name on the expanded 246 * parameter value, solely based on comparing the SIDs in token. 247 * 248 * The other use is the netgroup check when using @group or &group. 249 */ 250 251BOOL is_share_read_only_for_token(const char *username, 252 struct nt_user_token *token, int snum) 253{ 254 BOOL result = lp_readonly(snum); 255 256 if (lp_readlist(snum) != NULL) { 257 if (token_contains_name_in_list(username, 258 lp_servicename(snum), token, 259 lp_readlist(snum))) { 260 result = True; 261 } 262 } 263 264 if (lp_writelist(snum) != NULL) { 265 if (token_contains_name_in_list(username, 266 lp_servicename(snum), token, 267 lp_writelist(snum))) { 268 result = False; 269 } 270 } 271 272 DEBUG(10,("is_share_read_only_for_user: share %s is %s for unix user " 273 "%s\n", lp_servicename(snum), 274 result ? "read-only" : "read-write", username)); 275 276 return result; 277} 278