1*38c8a9a5SSteve French // SPDX-License-Identifier: GPL-2.0-or-later 2*38c8a9a5SSteve French /* 3*38c8a9a5SSteve French * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4*38c8a9a5SSteve French * Copyright (C) 2018 Namjae Jeon <linkinjeon@kernel.org> 5*38c8a9a5SSteve French */ 6*38c8a9a5SSteve French 7*38c8a9a5SSteve French #include <linux/user_namespace.h> 8*38c8a9a5SSteve French 9*38c8a9a5SSteve French #include "smb_common.h" 10*38c8a9a5SSteve French #include "server.h" 11*38c8a9a5SSteve French #include "misc.h" 12*38c8a9a5SSteve French #include "smbstatus.h" 13*38c8a9a5SSteve French #include "connection.h" 14*38c8a9a5SSteve French #include "ksmbd_work.h" 15*38c8a9a5SSteve French #include "mgmt/user_session.h" 16*38c8a9a5SSteve French #include "mgmt/user_config.h" 17*38c8a9a5SSteve French #include "mgmt/tree_connect.h" 18*38c8a9a5SSteve French #include "mgmt/share_config.h" 19*38c8a9a5SSteve French 20*38c8a9a5SSteve French /*for shortname implementation */ 21*38c8a9a5SSteve French static const char basechars[43] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%"; 22*38c8a9a5SSteve French #define MANGLE_BASE (sizeof(basechars) / sizeof(char) - 1) 23*38c8a9a5SSteve French #define MAGIC_CHAR '~' 24*38c8a9a5SSteve French #define PERIOD '.' 25*38c8a9a5SSteve French #define mangle(V) ((char)(basechars[(V) % MANGLE_BASE])) 26*38c8a9a5SSteve French 27*38c8a9a5SSteve French struct smb_protocol { 28*38c8a9a5SSteve French int index; 29*38c8a9a5SSteve French char *name; 30*38c8a9a5SSteve French char *prot; 31*38c8a9a5SSteve French __u16 prot_id; 32*38c8a9a5SSteve French }; 33*38c8a9a5SSteve French 34*38c8a9a5SSteve French static struct smb_protocol smb1_protos[] = { 35*38c8a9a5SSteve French { 36*38c8a9a5SSteve French SMB21_PROT, 37*38c8a9a5SSteve French "\2SMB 2.1", 38*38c8a9a5SSteve French "SMB2_10", 39*38c8a9a5SSteve French SMB21_PROT_ID 40*38c8a9a5SSteve French }, 41*38c8a9a5SSteve French { 42*38c8a9a5SSteve French SMB2X_PROT, 43*38c8a9a5SSteve French "\2SMB 2.???", 44*38c8a9a5SSteve French "SMB2_22", 45*38c8a9a5SSteve French SMB2X_PROT_ID 46*38c8a9a5SSteve French }, 47*38c8a9a5SSteve French }; 48*38c8a9a5SSteve French 49*38c8a9a5SSteve French static struct smb_protocol smb2_protos[] = { 50*38c8a9a5SSteve French { 51*38c8a9a5SSteve French SMB21_PROT, 52*38c8a9a5SSteve French "\2SMB 2.1", 53*38c8a9a5SSteve French "SMB2_10", 54*38c8a9a5SSteve French SMB21_PROT_ID 55*38c8a9a5SSteve French }, 56*38c8a9a5SSteve French { 57*38c8a9a5SSteve French SMB30_PROT, 58*38c8a9a5SSteve French "\2SMB 3.0", 59*38c8a9a5SSteve French "SMB3_00", 60*38c8a9a5SSteve French SMB30_PROT_ID 61*38c8a9a5SSteve French }, 62*38c8a9a5SSteve French { 63*38c8a9a5SSteve French SMB302_PROT, 64*38c8a9a5SSteve French "\2SMB 3.02", 65*38c8a9a5SSteve French "SMB3_02", 66*38c8a9a5SSteve French SMB302_PROT_ID 67*38c8a9a5SSteve French }, 68*38c8a9a5SSteve French { 69*38c8a9a5SSteve French SMB311_PROT, 70*38c8a9a5SSteve French "\2SMB 3.1.1", 71*38c8a9a5SSteve French "SMB3_11", 72*38c8a9a5SSteve French SMB311_PROT_ID 73*38c8a9a5SSteve French }, 74*38c8a9a5SSteve French }; 75*38c8a9a5SSteve French 76*38c8a9a5SSteve French unsigned int ksmbd_server_side_copy_max_chunk_count(void) 77*38c8a9a5SSteve French { 78*38c8a9a5SSteve French return 256; 79*38c8a9a5SSteve French } 80*38c8a9a5SSteve French 81*38c8a9a5SSteve French unsigned int ksmbd_server_side_copy_max_chunk_size(void) 82*38c8a9a5SSteve French { 83*38c8a9a5SSteve French return (2U << 30) - 1; 84*38c8a9a5SSteve French } 85*38c8a9a5SSteve French 86*38c8a9a5SSteve French unsigned int ksmbd_server_side_copy_max_total_size(void) 87*38c8a9a5SSteve French { 88*38c8a9a5SSteve French return (2U << 30) - 1; 89*38c8a9a5SSteve French } 90*38c8a9a5SSteve French 91*38c8a9a5SSteve French inline int ksmbd_min_protocol(void) 92*38c8a9a5SSteve French { 93*38c8a9a5SSteve French return SMB21_PROT; 94*38c8a9a5SSteve French } 95*38c8a9a5SSteve French 96*38c8a9a5SSteve French inline int ksmbd_max_protocol(void) 97*38c8a9a5SSteve French { 98*38c8a9a5SSteve French return SMB311_PROT; 99*38c8a9a5SSteve French } 100*38c8a9a5SSteve French 101*38c8a9a5SSteve French int ksmbd_lookup_protocol_idx(char *str) 102*38c8a9a5SSteve French { 103*38c8a9a5SSteve French int offt = ARRAY_SIZE(smb1_protos) - 1; 104*38c8a9a5SSteve French int len = strlen(str); 105*38c8a9a5SSteve French 106*38c8a9a5SSteve French while (offt >= 0) { 107*38c8a9a5SSteve French if (!strncmp(str, smb1_protos[offt].prot, len)) { 108*38c8a9a5SSteve French ksmbd_debug(SMB, "selected %s dialect idx = %d\n", 109*38c8a9a5SSteve French smb1_protos[offt].prot, offt); 110*38c8a9a5SSteve French return smb1_protos[offt].index; 111*38c8a9a5SSteve French } 112*38c8a9a5SSteve French offt--; 113*38c8a9a5SSteve French } 114*38c8a9a5SSteve French 115*38c8a9a5SSteve French offt = ARRAY_SIZE(smb2_protos) - 1; 116*38c8a9a5SSteve French while (offt >= 0) { 117*38c8a9a5SSteve French if (!strncmp(str, smb2_protos[offt].prot, len)) { 118*38c8a9a5SSteve French ksmbd_debug(SMB, "selected %s dialect idx = %d\n", 119*38c8a9a5SSteve French smb2_protos[offt].prot, offt); 120*38c8a9a5SSteve French return smb2_protos[offt].index; 121*38c8a9a5SSteve French } 122*38c8a9a5SSteve French offt--; 123*38c8a9a5SSteve French } 124*38c8a9a5SSteve French return -1; 125*38c8a9a5SSteve French } 126*38c8a9a5SSteve French 127*38c8a9a5SSteve French /** 128*38c8a9a5SSteve French * ksmbd_verify_smb_message() - check for valid smb2 request header 129*38c8a9a5SSteve French * @work: smb work 130*38c8a9a5SSteve French * 131*38c8a9a5SSteve French * check for valid smb signature and packet direction(request/response) 132*38c8a9a5SSteve French * 133*38c8a9a5SSteve French * Return: 0 on success, otherwise -EINVAL 134*38c8a9a5SSteve French */ 135*38c8a9a5SSteve French int ksmbd_verify_smb_message(struct ksmbd_work *work) 136*38c8a9a5SSteve French { 137*38c8a9a5SSteve French struct smb2_hdr *smb2_hdr = ksmbd_req_buf_next(work); 138*38c8a9a5SSteve French struct smb_hdr *hdr; 139*38c8a9a5SSteve French 140*38c8a9a5SSteve French if (smb2_hdr->ProtocolId == SMB2_PROTO_NUMBER) 141*38c8a9a5SSteve French return ksmbd_smb2_check_message(work); 142*38c8a9a5SSteve French 143*38c8a9a5SSteve French hdr = work->request_buf; 144*38c8a9a5SSteve French if (*(__le32 *)hdr->Protocol == SMB1_PROTO_NUMBER && 145*38c8a9a5SSteve French hdr->Command == SMB_COM_NEGOTIATE) { 146*38c8a9a5SSteve French work->conn->outstanding_credits++; 147*38c8a9a5SSteve French return 0; 148*38c8a9a5SSteve French } 149*38c8a9a5SSteve French 150*38c8a9a5SSteve French return -EINVAL; 151*38c8a9a5SSteve French } 152*38c8a9a5SSteve French 153*38c8a9a5SSteve French /** 154*38c8a9a5SSteve French * ksmbd_smb_request() - check for valid smb request type 155*38c8a9a5SSteve French * @conn: connection instance 156*38c8a9a5SSteve French * 157*38c8a9a5SSteve French * Return: true on success, otherwise false 158*38c8a9a5SSteve French */ 159*38c8a9a5SSteve French bool ksmbd_smb_request(struct ksmbd_conn *conn) 160*38c8a9a5SSteve French { 161*38c8a9a5SSteve French return conn->request_buf[0] == 0; 162*38c8a9a5SSteve French } 163*38c8a9a5SSteve French 164*38c8a9a5SSteve French static bool supported_protocol(int idx) 165*38c8a9a5SSteve French { 166*38c8a9a5SSteve French if (idx == SMB2X_PROT && 167*38c8a9a5SSteve French (server_conf.min_protocol >= SMB21_PROT || 168*38c8a9a5SSteve French server_conf.max_protocol <= SMB311_PROT)) 169*38c8a9a5SSteve French return true; 170*38c8a9a5SSteve French 171*38c8a9a5SSteve French return (server_conf.min_protocol <= idx && 172*38c8a9a5SSteve French idx <= server_conf.max_protocol); 173*38c8a9a5SSteve French } 174*38c8a9a5SSteve French 175*38c8a9a5SSteve French static char *next_dialect(char *dialect, int *next_off, int bcount) 176*38c8a9a5SSteve French { 177*38c8a9a5SSteve French dialect = dialect + *next_off; 178*38c8a9a5SSteve French *next_off = strnlen(dialect, bcount); 179*38c8a9a5SSteve French if (dialect[*next_off] != '\0') 180*38c8a9a5SSteve French return NULL; 181*38c8a9a5SSteve French return dialect; 182*38c8a9a5SSteve French } 183*38c8a9a5SSteve French 184*38c8a9a5SSteve French static int ksmbd_lookup_dialect_by_name(char *cli_dialects, __le16 byte_count) 185*38c8a9a5SSteve French { 186*38c8a9a5SSteve French int i, seq_num, bcount, next; 187*38c8a9a5SSteve French char *dialect; 188*38c8a9a5SSteve French 189*38c8a9a5SSteve French for (i = ARRAY_SIZE(smb1_protos) - 1; i >= 0; i--) { 190*38c8a9a5SSteve French seq_num = 0; 191*38c8a9a5SSteve French next = 0; 192*38c8a9a5SSteve French dialect = cli_dialects; 193*38c8a9a5SSteve French bcount = le16_to_cpu(byte_count); 194*38c8a9a5SSteve French do { 195*38c8a9a5SSteve French dialect = next_dialect(dialect, &next, bcount); 196*38c8a9a5SSteve French if (!dialect) 197*38c8a9a5SSteve French break; 198*38c8a9a5SSteve French ksmbd_debug(SMB, "client requested dialect %s\n", 199*38c8a9a5SSteve French dialect); 200*38c8a9a5SSteve French if (!strcmp(dialect, smb1_protos[i].name)) { 201*38c8a9a5SSteve French if (supported_protocol(smb1_protos[i].index)) { 202*38c8a9a5SSteve French ksmbd_debug(SMB, 203*38c8a9a5SSteve French "selected %s dialect\n", 204*38c8a9a5SSteve French smb1_protos[i].name); 205*38c8a9a5SSteve French if (smb1_protos[i].index == SMB1_PROT) 206*38c8a9a5SSteve French return seq_num; 207*38c8a9a5SSteve French return smb1_protos[i].prot_id; 208*38c8a9a5SSteve French } 209*38c8a9a5SSteve French } 210*38c8a9a5SSteve French seq_num++; 211*38c8a9a5SSteve French bcount -= (++next); 212*38c8a9a5SSteve French } while (bcount > 0); 213*38c8a9a5SSteve French } 214*38c8a9a5SSteve French 215*38c8a9a5SSteve French return BAD_PROT_ID; 216*38c8a9a5SSteve French } 217*38c8a9a5SSteve French 218*38c8a9a5SSteve French int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count) 219*38c8a9a5SSteve French { 220*38c8a9a5SSteve French int i; 221*38c8a9a5SSteve French int count; 222*38c8a9a5SSteve French 223*38c8a9a5SSteve French for (i = ARRAY_SIZE(smb2_protos) - 1; i >= 0; i--) { 224*38c8a9a5SSteve French count = le16_to_cpu(dialects_count); 225*38c8a9a5SSteve French while (--count >= 0) { 226*38c8a9a5SSteve French ksmbd_debug(SMB, "client requested dialect 0x%x\n", 227*38c8a9a5SSteve French le16_to_cpu(cli_dialects[count])); 228*38c8a9a5SSteve French if (le16_to_cpu(cli_dialects[count]) != 229*38c8a9a5SSteve French smb2_protos[i].prot_id) 230*38c8a9a5SSteve French continue; 231*38c8a9a5SSteve French 232*38c8a9a5SSteve French if (supported_protocol(smb2_protos[i].index)) { 233*38c8a9a5SSteve French ksmbd_debug(SMB, "selected %s dialect\n", 234*38c8a9a5SSteve French smb2_protos[i].name); 235*38c8a9a5SSteve French return smb2_protos[i].prot_id; 236*38c8a9a5SSteve French } 237*38c8a9a5SSteve French } 238*38c8a9a5SSteve French } 239*38c8a9a5SSteve French 240*38c8a9a5SSteve French return BAD_PROT_ID; 241*38c8a9a5SSteve French } 242*38c8a9a5SSteve French 243*38c8a9a5SSteve French static int ksmbd_negotiate_smb_dialect(void *buf) 244*38c8a9a5SSteve French { 245*38c8a9a5SSteve French int smb_buf_length = get_rfc1002_len(buf); 246*38c8a9a5SSteve French __le32 proto = ((struct smb2_hdr *)smb2_get_msg(buf))->ProtocolId; 247*38c8a9a5SSteve French 248*38c8a9a5SSteve French if (proto == SMB2_PROTO_NUMBER) { 249*38c8a9a5SSteve French struct smb2_negotiate_req *req; 250*38c8a9a5SSteve French int smb2_neg_size = 251*38c8a9a5SSteve French offsetof(struct smb2_negotiate_req, Dialects); 252*38c8a9a5SSteve French 253*38c8a9a5SSteve French req = (struct smb2_negotiate_req *)smb2_get_msg(buf); 254*38c8a9a5SSteve French if (smb2_neg_size > smb_buf_length) 255*38c8a9a5SSteve French goto err_out; 256*38c8a9a5SSteve French 257*38c8a9a5SSteve French if (smb2_neg_size + le16_to_cpu(req->DialectCount) * sizeof(__le16) > 258*38c8a9a5SSteve French smb_buf_length) 259*38c8a9a5SSteve French goto err_out; 260*38c8a9a5SSteve French 261*38c8a9a5SSteve French return ksmbd_lookup_dialect_by_id(req->Dialects, 262*38c8a9a5SSteve French req->DialectCount); 263*38c8a9a5SSteve French } 264*38c8a9a5SSteve French 265*38c8a9a5SSteve French proto = *(__le32 *)((struct smb_hdr *)buf)->Protocol; 266*38c8a9a5SSteve French if (proto == SMB1_PROTO_NUMBER) { 267*38c8a9a5SSteve French struct smb_negotiate_req *req; 268*38c8a9a5SSteve French 269*38c8a9a5SSteve French req = (struct smb_negotiate_req *)buf; 270*38c8a9a5SSteve French if (le16_to_cpu(req->ByteCount) < 2) 271*38c8a9a5SSteve French goto err_out; 272*38c8a9a5SSteve French 273*38c8a9a5SSteve French if (offsetof(struct smb_negotiate_req, DialectsArray) - 4 + 274*38c8a9a5SSteve French le16_to_cpu(req->ByteCount) > smb_buf_length) { 275*38c8a9a5SSteve French goto err_out; 276*38c8a9a5SSteve French } 277*38c8a9a5SSteve French 278*38c8a9a5SSteve French return ksmbd_lookup_dialect_by_name(req->DialectsArray, 279*38c8a9a5SSteve French req->ByteCount); 280*38c8a9a5SSteve French } 281*38c8a9a5SSteve French 282*38c8a9a5SSteve French err_out: 283*38c8a9a5SSteve French return BAD_PROT_ID; 284*38c8a9a5SSteve French } 285*38c8a9a5SSteve French 286*38c8a9a5SSteve French #define SMB_COM_NEGOTIATE_EX 0x0 287*38c8a9a5SSteve French 288*38c8a9a5SSteve French /** 289*38c8a9a5SSteve French * get_smb1_cmd_val() - get smb command value from smb header 290*38c8a9a5SSteve French * @work: smb work containing smb header 291*38c8a9a5SSteve French * 292*38c8a9a5SSteve French * Return: smb command value 293*38c8a9a5SSteve French */ 294*38c8a9a5SSteve French static u16 get_smb1_cmd_val(struct ksmbd_work *work) 295*38c8a9a5SSteve French { 296*38c8a9a5SSteve French return SMB_COM_NEGOTIATE_EX; 297*38c8a9a5SSteve French } 298*38c8a9a5SSteve French 299*38c8a9a5SSteve French /** 300*38c8a9a5SSteve French * init_smb1_rsp_hdr() - initialize smb negotiate response header 301*38c8a9a5SSteve French * @work: smb work containing smb request 302*38c8a9a5SSteve French * 303*38c8a9a5SSteve French * Return: 0 on success, otherwise -EINVAL 304*38c8a9a5SSteve French */ 305*38c8a9a5SSteve French static int init_smb1_rsp_hdr(struct ksmbd_work *work) 306*38c8a9a5SSteve French { 307*38c8a9a5SSteve French struct smb_hdr *rsp_hdr = (struct smb_hdr *)work->response_buf; 308*38c8a9a5SSteve French struct smb_hdr *rcv_hdr = (struct smb_hdr *)work->request_buf; 309*38c8a9a5SSteve French 310*38c8a9a5SSteve French /* 311*38c8a9a5SSteve French * Remove 4 byte direct TCP header. 312*38c8a9a5SSteve French */ 313*38c8a9a5SSteve French *(__be32 *)work->response_buf = 314*38c8a9a5SSteve French cpu_to_be32(sizeof(struct smb_hdr) - 4); 315*38c8a9a5SSteve French 316*38c8a9a5SSteve French rsp_hdr->Command = SMB_COM_NEGOTIATE; 317*38c8a9a5SSteve French *(__le32 *)rsp_hdr->Protocol = SMB1_PROTO_NUMBER; 318*38c8a9a5SSteve French rsp_hdr->Flags = SMBFLG_RESPONSE; 319*38c8a9a5SSteve French rsp_hdr->Flags2 = SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS | 320*38c8a9a5SSteve French SMBFLG2_EXT_SEC | SMBFLG2_IS_LONG_NAME; 321*38c8a9a5SSteve French rsp_hdr->Pid = rcv_hdr->Pid; 322*38c8a9a5SSteve French rsp_hdr->Mid = rcv_hdr->Mid; 323*38c8a9a5SSteve French return 0; 324*38c8a9a5SSteve French } 325*38c8a9a5SSteve French 326*38c8a9a5SSteve French /** 327*38c8a9a5SSteve French * smb1_check_user_session() - check for valid session for a user 328*38c8a9a5SSteve French * @work: smb work containing smb request buffer 329*38c8a9a5SSteve French * 330*38c8a9a5SSteve French * Return: 0 on success, otherwise error 331*38c8a9a5SSteve French */ 332*38c8a9a5SSteve French static int smb1_check_user_session(struct ksmbd_work *work) 333*38c8a9a5SSteve French { 334*38c8a9a5SSteve French unsigned int cmd = work->conn->ops->get_cmd_val(work); 335*38c8a9a5SSteve French 336*38c8a9a5SSteve French if (cmd == SMB_COM_NEGOTIATE_EX) 337*38c8a9a5SSteve French return 0; 338*38c8a9a5SSteve French 339*38c8a9a5SSteve French return -EINVAL; 340*38c8a9a5SSteve French } 341*38c8a9a5SSteve French 342*38c8a9a5SSteve French /** 343*38c8a9a5SSteve French * smb1_allocate_rsp_buf() - allocate response buffer for a command 344*38c8a9a5SSteve French * @work: smb work containing smb request 345*38c8a9a5SSteve French * 346*38c8a9a5SSteve French * Return: 0 on success, otherwise -ENOMEM 347*38c8a9a5SSteve French */ 348*38c8a9a5SSteve French static int smb1_allocate_rsp_buf(struct ksmbd_work *work) 349*38c8a9a5SSteve French { 350*38c8a9a5SSteve French work->response_buf = kmalloc(MAX_CIFS_SMALL_BUFFER_SIZE, 351*38c8a9a5SSteve French GFP_KERNEL | __GFP_ZERO); 352*38c8a9a5SSteve French work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE; 353*38c8a9a5SSteve French 354*38c8a9a5SSteve French if (!work->response_buf) { 355*38c8a9a5SSteve French pr_err("Failed to allocate %u bytes buffer\n", 356*38c8a9a5SSteve French MAX_CIFS_SMALL_BUFFER_SIZE); 357*38c8a9a5SSteve French return -ENOMEM; 358*38c8a9a5SSteve French } 359*38c8a9a5SSteve French 360*38c8a9a5SSteve French return 0; 361*38c8a9a5SSteve French } 362*38c8a9a5SSteve French 363*38c8a9a5SSteve French static struct smb_version_ops smb1_server_ops = { 364*38c8a9a5SSteve French .get_cmd_val = get_smb1_cmd_val, 365*38c8a9a5SSteve French .init_rsp_hdr = init_smb1_rsp_hdr, 366*38c8a9a5SSteve French .allocate_rsp_buf = smb1_allocate_rsp_buf, 367*38c8a9a5SSteve French .check_user_session = smb1_check_user_session, 368*38c8a9a5SSteve French }; 369*38c8a9a5SSteve French 370*38c8a9a5SSteve French static int smb1_negotiate(struct ksmbd_work *work) 371*38c8a9a5SSteve French { 372*38c8a9a5SSteve French return ksmbd_smb_negotiate_common(work, SMB_COM_NEGOTIATE); 373*38c8a9a5SSteve French } 374*38c8a9a5SSteve French 375*38c8a9a5SSteve French static struct smb_version_cmds smb1_server_cmds[1] = { 376*38c8a9a5SSteve French [SMB_COM_NEGOTIATE_EX] = { .proc = smb1_negotiate, }, 377*38c8a9a5SSteve French }; 378*38c8a9a5SSteve French 379*38c8a9a5SSteve French static void init_smb1_server(struct ksmbd_conn *conn) 380*38c8a9a5SSteve French { 381*38c8a9a5SSteve French conn->ops = &smb1_server_ops; 382*38c8a9a5SSteve French conn->cmds = smb1_server_cmds; 383*38c8a9a5SSteve French conn->max_cmds = ARRAY_SIZE(smb1_server_cmds); 384*38c8a9a5SSteve French } 385*38c8a9a5SSteve French 386*38c8a9a5SSteve French void ksmbd_init_smb_server(struct ksmbd_work *work) 387*38c8a9a5SSteve French { 388*38c8a9a5SSteve French struct ksmbd_conn *conn = work->conn; 389*38c8a9a5SSteve French __le32 proto; 390*38c8a9a5SSteve French 391*38c8a9a5SSteve French if (conn->need_neg == false) 392*38c8a9a5SSteve French return; 393*38c8a9a5SSteve French 394*38c8a9a5SSteve French proto = *(__le32 *)((struct smb_hdr *)work->request_buf)->Protocol; 395*38c8a9a5SSteve French if (proto == SMB1_PROTO_NUMBER) 396*38c8a9a5SSteve French init_smb1_server(conn); 397*38c8a9a5SSteve French else 398*38c8a9a5SSteve French init_smb3_11_server(conn); 399*38c8a9a5SSteve French } 400*38c8a9a5SSteve French 401*38c8a9a5SSteve French int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level, 402*38c8a9a5SSteve French struct ksmbd_file *dir, 403*38c8a9a5SSteve French struct ksmbd_dir_info *d_info, 404*38c8a9a5SSteve French char *search_pattern, 405*38c8a9a5SSteve French int (*fn)(struct ksmbd_conn *, int, 406*38c8a9a5SSteve French struct ksmbd_dir_info *, 407*38c8a9a5SSteve French struct ksmbd_kstat *)) 408*38c8a9a5SSteve French { 409*38c8a9a5SSteve French int i, rc = 0; 410*38c8a9a5SSteve French struct ksmbd_conn *conn = work->conn; 411*38c8a9a5SSteve French struct mnt_idmap *idmap = file_mnt_idmap(dir->filp); 412*38c8a9a5SSteve French 413*38c8a9a5SSteve French for (i = 0; i < 2; i++) { 414*38c8a9a5SSteve French struct kstat kstat; 415*38c8a9a5SSteve French struct ksmbd_kstat ksmbd_kstat; 416*38c8a9a5SSteve French struct dentry *dentry; 417*38c8a9a5SSteve French 418*38c8a9a5SSteve French if (!dir->dot_dotdot[i]) { /* fill dot entry info */ 419*38c8a9a5SSteve French if (i == 0) { 420*38c8a9a5SSteve French d_info->name = "."; 421*38c8a9a5SSteve French d_info->name_len = 1; 422*38c8a9a5SSteve French dentry = dir->filp->f_path.dentry; 423*38c8a9a5SSteve French } else { 424*38c8a9a5SSteve French d_info->name = ".."; 425*38c8a9a5SSteve French d_info->name_len = 2; 426*38c8a9a5SSteve French dentry = dir->filp->f_path.dentry->d_parent; 427*38c8a9a5SSteve French } 428*38c8a9a5SSteve French 429*38c8a9a5SSteve French if (!match_pattern(d_info->name, d_info->name_len, 430*38c8a9a5SSteve French search_pattern)) { 431*38c8a9a5SSteve French dir->dot_dotdot[i] = 1; 432*38c8a9a5SSteve French continue; 433*38c8a9a5SSteve French } 434*38c8a9a5SSteve French 435*38c8a9a5SSteve French ksmbd_kstat.kstat = &kstat; 436*38c8a9a5SSteve French ksmbd_vfs_fill_dentry_attrs(work, 437*38c8a9a5SSteve French idmap, 438*38c8a9a5SSteve French dentry, 439*38c8a9a5SSteve French &ksmbd_kstat); 440*38c8a9a5SSteve French rc = fn(conn, info_level, d_info, &ksmbd_kstat); 441*38c8a9a5SSteve French if (rc) 442*38c8a9a5SSteve French break; 443*38c8a9a5SSteve French if (d_info->out_buf_len <= 0) 444*38c8a9a5SSteve French break; 445*38c8a9a5SSteve French 446*38c8a9a5SSteve French dir->dot_dotdot[i] = 1; 447*38c8a9a5SSteve French if (d_info->flags & SMB2_RETURN_SINGLE_ENTRY) { 448*38c8a9a5SSteve French d_info->out_buf_len = 0; 449*38c8a9a5SSteve French break; 450*38c8a9a5SSteve French } 451*38c8a9a5SSteve French } 452*38c8a9a5SSteve French } 453*38c8a9a5SSteve French 454*38c8a9a5SSteve French return rc; 455*38c8a9a5SSteve French } 456*38c8a9a5SSteve French 457*38c8a9a5SSteve French /** 458*38c8a9a5SSteve French * ksmbd_extract_shortname() - get shortname from long filename 459*38c8a9a5SSteve French * @conn: connection instance 460*38c8a9a5SSteve French * @longname: source long filename 461*38c8a9a5SSteve French * @shortname: destination short filename 462*38c8a9a5SSteve French * 463*38c8a9a5SSteve French * Return: shortname length or 0 when source long name is '.' or '..' 464*38c8a9a5SSteve French * TODO: Though this function comforms the restriction of 8.3 Filename spec, 465*38c8a9a5SSteve French * but the result is different with Windows 7's one. need to check. 466*38c8a9a5SSteve French */ 467*38c8a9a5SSteve French int ksmbd_extract_shortname(struct ksmbd_conn *conn, const char *longname, 468*38c8a9a5SSteve French char *shortname) 469*38c8a9a5SSteve French { 470*38c8a9a5SSteve French const char *p; 471*38c8a9a5SSteve French char base[9], extension[4]; 472*38c8a9a5SSteve French char out[13] = {0}; 473*38c8a9a5SSteve French int baselen = 0; 474*38c8a9a5SSteve French int extlen = 0, len = 0; 475*38c8a9a5SSteve French unsigned int csum = 0; 476*38c8a9a5SSteve French const unsigned char *ptr; 477*38c8a9a5SSteve French bool dot_present = true; 478*38c8a9a5SSteve French 479*38c8a9a5SSteve French p = longname; 480*38c8a9a5SSteve French if ((*p == '.') || (!(strcmp(p, "..")))) { 481*38c8a9a5SSteve French /*no mangling required */ 482*38c8a9a5SSteve French return 0; 483*38c8a9a5SSteve French } 484*38c8a9a5SSteve French 485*38c8a9a5SSteve French p = strrchr(longname, '.'); 486*38c8a9a5SSteve French if (p == longname) { /*name starts with a dot*/ 487*38c8a9a5SSteve French strscpy(extension, "___", strlen("___")); 488*38c8a9a5SSteve French } else { 489*38c8a9a5SSteve French if (p) { 490*38c8a9a5SSteve French p++; 491*38c8a9a5SSteve French while (*p && extlen < 3) { 492*38c8a9a5SSteve French if (*p != '.') 493*38c8a9a5SSteve French extension[extlen++] = toupper(*p); 494*38c8a9a5SSteve French p++; 495*38c8a9a5SSteve French } 496*38c8a9a5SSteve French extension[extlen] = '\0'; 497*38c8a9a5SSteve French } else { 498*38c8a9a5SSteve French dot_present = false; 499*38c8a9a5SSteve French } 500*38c8a9a5SSteve French } 501*38c8a9a5SSteve French 502*38c8a9a5SSteve French p = longname; 503*38c8a9a5SSteve French if (*p == '.') { 504*38c8a9a5SSteve French p++; 505*38c8a9a5SSteve French longname++; 506*38c8a9a5SSteve French } 507*38c8a9a5SSteve French while (*p && (baselen < 5)) { 508*38c8a9a5SSteve French if (*p != '.') 509*38c8a9a5SSteve French base[baselen++] = toupper(*p); 510*38c8a9a5SSteve French p++; 511*38c8a9a5SSteve French } 512*38c8a9a5SSteve French 513*38c8a9a5SSteve French base[baselen] = MAGIC_CHAR; 514*38c8a9a5SSteve French memcpy(out, base, baselen + 1); 515*38c8a9a5SSteve French 516*38c8a9a5SSteve French ptr = longname; 517*38c8a9a5SSteve French len = strlen(longname); 518*38c8a9a5SSteve French for (; len > 0; len--, ptr++) 519*38c8a9a5SSteve French csum += *ptr; 520*38c8a9a5SSteve French 521*38c8a9a5SSteve French csum = csum % (MANGLE_BASE * MANGLE_BASE); 522*38c8a9a5SSteve French out[baselen + 1] = mangle(csum / MANGLE_BASE); 523*38c8a9a5SSteve French out[baselen + 2] = mangle(csum); 524*38c8a9a5SSteve French out[baselen + 3] = PERIOD; 525*38c8a9a5SSteve French 526*38c8a9a5SSteve French if (dot_present) 527*38c8a9a5SSteve French memcpy(&out[baselen + 4], extension, 4); 528*38c8a9a5SSteve French else 529*38c8a9a5SSteve French out[baselen + 4] = '\0'; 530*38c8a9a5SSteve French smbConvertToUTF16((__le16 *)shortname, out, PATH_MAX, 531*38c8a9a5SSteve French conn->local_nls, 0); 532*38c8a9a5SSteve French len = strlen(out) * 2; 533*38c8a9a5SSteve French return len; 534*38c8a9a5SSteve French } 535*38c8a9a5SSteve French 536*38c8a9a5SSteve French static int __smb2_negotiate(struct ksmbd_conn *conn) 537*38c8a9a5SSteve French { 538*38c8a9a5SSteve French return (conn->dialect >= SMB20_PROT_ID && 539*38c8a9a5SSteve French conn->dialect <= SMB311_PROT_ID); 540*38c8a9a5SSteve French } 541*38c8a9a5SSteve French 542*38c8a9a5SSteve French static int smb_handle_negotiate(struct ksmbd_work *work) 543*38c8a9a5SSteve French { 544*38c8a9a5SSteve French struct smb_negotiate_rsp *neg_rsp = work->response_buf; 545*38c8a9a5SSteve French 546*38c8a9a5SSteve French ksmbd_debug(SMB, "Unsupported SMB1 protocol\n"); 547*38c8a9a5SSteve French 548*38c8a9a5SSteve French /* Add 2 byte bcc and 2 byte DialectIndex. */ 549*38c8a9a5SSteve French inc_rfc1001_len(work->response_buf, 4); 550*38c8a9a5SSteve French neg_rsp->hdr.Status.CifsError = STATUS_SUCCESS; 551*38c8a9a5SSteve French 552*38c8a9a5SSteve French neg_rsp->hdr.WordCount = 1; 553*38c8a9a5SSteve French neg_rsp->DialectIndex = cpu_to_le16(work->conn->dialect); 554*38c8a9a5SSteve French neg_rsp->ByteCount = 0; 555*38c8a9a5SSteve French return 0; 556*38c8a9a5SSteve French } 557*38c8a9a5SSteve French 558*38c8a9a5SSteve French int ksmbd_smb_negotiate_common(struct ksmbd_work *work, unsigned int command) 559*38c8a9a5SSteve French { 560*38c8a9a5SSteve French struct ksmbd_conn *conn = work->conn; 561*38c8a9a5SSteve French int ret; 562*38c8a9a5SSteve French 563*38c8a9a5SSteve French conn->dialect = 564*38c8a9a5SSteve French ksmbd_negotiate_smb_dialect(work->request_buf); 565*38c8a9a5SSteve French ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect); 566*38c8a9a5SSteve French 567*38c8a9a5SSteve French if (command == SMB2_NEGOTIATE_HE) { 568*38c8a9a5SSteve French ret = smb2_handle_negotiate(work); 569*38c8a9a5SSteve French return ret; 570*38c8a9a5SSteve French } 571*38c8a9a5SSteve French 572*38c8a9a5SSteve French if (command == SMB_COM_NEGOTIATE) { 573*38c8a9a5SSteve French if (__smb2_negotiate(conn)) { 574*38c8a9a5SSteve French init_smb3_11_server(conn); 575*38c8a9a5SSteve French init_smb2_neg_rsp(work); 576*38c8a9a5SSteve French ksmbd_debug(SMB, "Upgrade to SMB2 negotiation\n"); 577*38c8a9a5SSteve French return 0; 578*38c8a9a5SSteve French } 579*38c8a9a5SSteve French return smb_handle_negotiate(work); 580*38c8a9a5SSteve French } 581*38c8a9a5SSteve French 582*38c8a9a5SSteve French pr_err("Unknown SMB negotiation command: %u\n", command); 583*38c8a9a5SSteve French return -EINVAL; 584*38c8a9a5SSteve French } 585*38c8a9a5SSteve French 586*38c8a9a5SSteve French enum SHARED_MODE_ERRORS { 587*38c8a9a5SSteve French SHARE_DELETE_ERROR, 588*38c8a9a5SSteve French SHARE_READ_ERROR, 589*38c8a9a5SSteve French SHARE_WRITE_ERROR, 590*38c8a9a5SSteve French FILE_READ_ERROR, 591*38c8a9a5SSteve French FILE_WRITE_ERROR, 592*38c8a9a5SSteve French FILE_DELETE_ERROR, 593*38c8a9a5SSteve French }; 594*38c8a9a5SSteve French 595*38c8a9a5SSteve French static const char * const shared_mode_errors[] = { 596*38c8a9a5SSteve French "Current access mode does not permit SHARE_DELETE", 597*38c8a9a5SSteve French "Current access mode does not permit SHARE_READ", 598*38c8a9a5SSteve French "Current access mode does not permit SHARE_WRITE", 599*38c8a9a5SSteve French "Desired access mode does not permit FILE_READ", 600*38c8a9a5SSteve French "Desired access mode does not permit FILE_WRITE", 601*38c8a9a5SSteve French "Desired access mode does not permit FILE_DELETE", 602*38c8a9a5SSteve French }; 603*38c8a9a5SSteve French 604*38c8a9a5SSteve French static void smb_shared_mode_error(int error, struct ksmbd_file *prev_fp, 605*38c8a9a5SSteve French struct ksmbd_file *curr_fp) 606*38c8a9a5SSteve French { 607*38c8a9a5SSteve French ksmbd_debug(SMB, "%s\n", shared_mode_errors[error]); 608*38c8a9a5SSteve French ksmbd_debug(SMB, "Current mode: 0x%x Desired mode: 0x%x\n", 609*38c8a9a5SSteve French prev_fp->saccess, curr_fp->daccess); 610*38c8a9a5SSteve French } 611*38c8a9a5SSteve French 612*38c8a9a5SSteve French int ksmbd_smb_check_shared_mode(struct file *filp, struct ksmbd_file *curr_fp) 613*38c8a9a5SSteve French { 614*38c8a9a5SSteve French int rc = 0; 615*38c8a9a5SSteve French struct ksmbd_file *prev_fp; 616*38c8a9a5SSteve French 617*38c8a9a5SSteve French /* 618*38c8a9a5SSteve French * Lookup fp in master fp list, and check desired access and 619*38c8a9a5SSteve French * shared mode between previous open and current open. 620*38c8a9a5SSteve French */ 621*38c8a9a5SSteve French read_lock(&curr_fp->f_ci->m_lock); 622*38c8a9a5SSteve French list_for_each_entry(prev_fp, &curr_fp->f_ci->m_fp_list, node) { 623*38c8a9a5SSteve French if (file_inode(filp) != file_inode(prev_fp->filp)) 624*38c8a9a5SSteve French continue; 625*38c8a9a5SSteve French 626*38c8a9a5SSteve French if (filp == prev_fp->filp) 627*38c8a9a5SSteve French continue; 628*38c8a9a5SSteve French 629*38c8a9a5SSteve French if (ksmbd_stream_fd(prev_fp) && ksmbd_stream_fd(curr_fp)) 630*38c8a9a5SSteve French if (strcmp(prev_fp->stream.name, curr_fp->stream.name)) 631*38c8a9a5SSteve French continue; 632*38c8a9a5SSteve French 633*38c8a9a5SSteve French if (prev_fp->attrib_only != curr_fp->attrib_only) 634*38c8a9a5SSteve French continue; 635*38c8a9a5SSteve French 636*38c8a9a5SSteve French if (!(prev_fp->saccess & FILE_SHARE_DELETE_LE) && 637*38c8a9a5SSteve French curr_fp->daccess & FILE_DELETE_LE) { 638*38c8a9a5SSteve French smb_shared_mode_error(SHARE_DELETE_ERROR, 639*38c8a9a5SSteve French prev_fp, 640*38c8a9a5SSteve French curr_fp); 641*38c8a9a5SSteve French rc = -EPERM; 642*38c8a9a5SSteve French break; 643*38c8a9a5SSteve French } 644*38c8a9a5SSteve French 645*38c8a9a5SSteve French /* 646*38c8a9a5SSteve French * Only check FILE_SHARE_DELETE if stream opened and 647*38c8a9a5SSteve French * normal file opened. 648*38c8a9a5SSteve French */ 649*38c8a9a5SSteve French if (ksmbd_stream_fd(prev_fp) && !ksmbd_stream_fd(curr_fp)) 650*38c8a9a5SSteve French continue; 651*38c8a9a5SSteve French 652*38c8a9a5SSteve French if (!(prev_fp->saccess & FILE_SHARE_READ_LE) && 653*38c8a9a5SSteve French curr_fp->daccess & (FILE_EXECUTE_LE | FILE_READ_DATA_LE)) { 654*38c8a9a5SSteve French smb_shared_mode_error(SHARE_READ_ERROR, 655*38c8a9a5SSteve French prev_fp, 656*38c8a9a5SSteve French curr_fp); 657*38c8a9a5SSteve French rc = -EPERM; 658*38c8a9a5SSteve French break; 659*38c8a9a5SSteve French } 660*38c8a9a5SSteve French 661*38c8a9a5SSteve French if (!(prev_fp->saccess & FILE_SHARE_WRITE_LE) && 662*38c8a9a5SSteve French curr_fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE)) { 663*38c8a9a5SSteve French smb_shared_mode_error(SHARE_WRITE_ERROR, 664*38c8a9a5SSteve French prev_fp, 665*38c8a9a5SSteve French curr_fp); 666*38c8a9a5SSteve French rc = -EPERM; 667*38c8a9a5SSteve French break; 668*38c8a9a5SSteve French } 669*38c8a9a5SSteve French 670*38c8a9a5SSteve French if (prev_fp->daccess & (FILE_EXECUTE_LE | FILE_READ_DATA_LE) && 671*38c8a9a5SSteve French !(curr_fp->saccess & FILE_SHARE_READ_LE)) { 672*38c8a9a5SSteve French smb_shared_mode_error(FILE_READ_ERROR, 673*38c8a9a5SSteve French prev_fp, 674*38c8a9a5SSteve French curr_fp); 675*38c8a9a5SSteve French rc = -EPERM; 676*38c8a9a5SSteve French break; 677*38c8a9a5SSteve French } 678*38c8a9a5SSteve French 679*38c8a9a5SSteve French if (prev_fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE) && 680*38c8a9a5SSteve French !(curr_fp->saccess & FILE_SHARE_WRITE_LE)) { 681*38c8a9a5SSteve French smb_shared_mode_error(FILE_WRITE_ERROR, 682*38c8a9a5SSteve French prev_fp, 683*38c8a9a5SSteve French curr_fp); 684*38c8a9a5SSteve French rc = -EPERM; 685*38c8a9a5SSteve French break; 686*38c8a9a5SSteve French } 687*38c8a9a5SSteve French 688*38c8a9a5SSteve French if (prev_fp->daccess & FILE_DELETE_LE && 689*38c8a9a5SSteve French !(curr_fp->saccess & FILE_SHARE_DELETE_LE)) { 690*38c8a9a5SSteve French smb_shared_mode_error(FILE_DELETE_ERROR, 691*38c8a9a5SSteve French prev_fp, 692*38c8a9a5SSteve French curr_fp); 693*38c8a9a5SSteve French rc = -EPERM; 694*38c8a9a5SSteve French break; 695*38c8a9a5SSteve French } 696*38c8a9a5SSteve French } 697*38c8a9a5SSteve French read_unlock(&curr_fp->f_ci->m_lock); 698*38c8a9a5SSteve French 699*38c8a9a5SSteve French return rc; 700*38c8a9a5SSteve French } 701*38c8a9a5SSteve French 702*38c8a9a5SSteve French bool is_asterisk(char *p) 703*38c8a9a5SSteve French { 704*38c8a9a5SSteve French return p && p[0] == '*'; 705*38c8a9a5SSteve French } 706*38c8a9a5SSteve French 707*38c8a9a5SSteve French int ksmbd_override_fsids(struct ksmbd_work *work) 708*38c8a9a5SSteve French { 709*38c8a9a5SSteve French struct ksmbd_session *sess = work->sess; 710*38c8a9a5SSteve French struct ksmbd_share_config *share = work->tcon->share_conf; 711*38c8a9a5SSteve French struct cred *cred; 712*38c8a9a5SSteve French struct group_info *gi; 713*38c8a9a5SSteve French unsigned int uid; 714*38c8a9a5SSteve French unsigned int gid; 715*38c8a9a5SSteve French 716*38c8a9a5SSteve French uid = user_uid(sess->user); 717*38c8a9a5SSteve French gid = user_gid(sess->user); 718*38c8a9a5SSteve French if (share->force_uid != KSMBD_SHARE_INVALID_UID) 719*38c8a9a5SSteve French uid = share->force_uid; 720*38c8a9a5SSteve French if (share->force_gid != KSMBD_SHARE_INVALID_GID) 721*38c8a9a5SSteve French gid = share->force_gid; 722*38c8a9a5SSteve French 723*38c8a9a5SSteve French cred = prepare_kernel_cred(&init_task); 724*38c8a9a5SSteve French if (!cred) 725*38c8a9a5SSteve French return -ENOMEM; 726*38c8a9a5SSteve French 727*38c8a9a5SSteve French cred->fsuid = make_kuid(&init_user_ns, uid); 728*38c8a9a5SSteve French cred->fsgid = make_kgid(&init_user_ns, gid); 729*38c8a9a5SSteve French 730*38c8a9a5SSteve French gi = groups_alloc(0); 731*38c8a9a5SSteve French if (!gi) { 732*38c8a9a5SSteve French abort_creds(cred); 733*38c8a9a5SSteve French return -ENOMEM; 734*38c8a9a5SSteve French } 735*38c8a9a5SSteve French set_groups(cred, gi); 736*38c8a9a5SSteve French put_group_info(gi); 737*38c8a9a5SSteve French 738*38c8a9a5SSteve French if (!uid_eq(cred->fsuid, GLOBAL_ROOT_UID)) 739*38c8a9a5SSteve French cred->cap_effective = cap_drop_fs_set(cred->cap_effective); 740*38c8a9a5SSteve French 741*38c8a9a5SSteve French WARN_ON(work->saved_cred); 742*38c8a9a5SSteve French work->saved_cred = override_creds(cred); 743*38c8a9a5SSteve French if (!work->saved_cred) { 744*38c8a9a5SSteve French abort_creds(cred); 745*38c8a9a5SSteve French return -EINVAL; 746*38c8a9a5SSteve French } 747*38c8a9a5SSteve French return 0; 748*38c8a9a5SSteve French } 749*38c8a9a5SSteve French 750*38c8a9a5SSteve French void ksmbd_revert_fsids(struct ksmbd_work *work) 751*38c8a9a5SSteve French { 752*38c8a9a5SSteve French const struct cred *cred; 753*38c8a9a5SSteve French 754*38c8a9a5SSteve French WARN_ON(!work->saved_cred); 755*38c8a9a5SSteve French 756*38c8a9a5SSteve French cred = current_cred(); 757*38c8a9a5SSteve French revert_creds(work->saved_cred); 758*38c8a9a5SSteve French put_cred(cred); 759*38c8a9a5SSteve French work->saved_cred = NULL; 760*38c8a9a5SSteve French } 761*38c8a9a5SSteve French 762*38c8a9a5SSteve French __le32 smb_map_generic_desired_access(__le32 daccess) 763*38c8a9a5SSteve French { 764*38c8a9a5SSteve French if (daccess & FILE_GENERIC_READ_LE) { 765*38c8a9a5SSteve French daccess |= cpu_to_le32(GENERIC_READ_FLAGS); 766*38c8a9a5SSteve French daccess &= ~FILE_GENERIC_READ_LE; 767*38c8a9a5SSteve French } 768*38c8a9a5SSteve French 769*38c8a9a5SSteve French if (daccess & FILE_GENERIC_WRITE_LE) { 770*38c8a9a5SSteve French daccess |= cpu_to_le32(GENERIC_WRITE_FLAGS); 771*38c8a9a5SSteve French daccess &= ~FILE_GENERIC_WRITE_LE; 772*38c8a9a5SSteve French } 773*38c8a9a5SSteve French 774*38c8a9a5SSteve French if (daccess & FILE_GENERIC_EXECUTE_LE) { 775*38c8a9a5SSteve French daccess |= cpu_to_le32(GENERIC_EXECUTE_FLAGS); 776*38c8a9a5SSteve French daccess &= ~FILE_GENERIC_EXECUTE_LE; 777*38c8a9a5SSteve French } 778*38c8a9a5SSteve French 779*38c8a9a5SSteve French if (daccess & FILE_GENERIC_ALL_LE) { 780*38c8a9a5SSteve French daccess |= cpu_to_le32(GENERIC_ALL_FLAGS); 781*38c8a9a5SSteve French daccess &= ~FILE_GENERIC_ALL_LE; 782*38c8a9a5SSteve French } 783*38c8a9a5SSteve French 784*38c8a9a5SSteve French return daccess; 785*38c8a9a5SSteve French } 786