Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *   Copyright (C) 2018 Samsung Electronics Co., Ltd.
0004  *   Copyright (C) 2018 Namjae Jeon <linkinjeon@kernel.org>
0005  */
0006 
0007 #include "smb_common.h"
0008 #include "server.h"
0009 #include "misc.h"
0010 #include "smbstatus.h"
0011 #include "connection.h"
0012 #include "ksmbd_work.h"
0013 #include "mgmt/user_session.h"
0014 #include "mgmt/user_config.h"
0015 #include "mgmt/tree_connect.h"
0016 #include "mgmt/share_config.h"
0017 
0018 /*for shortname implementation */
0019 static const char basechars[43] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-!@#$%";
0020 #define MANGLE_BASE (sizeof(basechars) / sizeof(char) - 1)
0021 #define MAGIC_CHAR '~'
0022 #define PERIOD '.'
0023 #define mangle(V) ((char)(basechars[(V) % MANGLE_BASE]))
0024 
0025 struct smb_protocol {
0026     int     index;
0027     char        *name;
0028     char        *prot;
0029     __u16       prot_id;
0030 };
0031 
0032 static struct smb_protocol smb1_protos[] = {
0033     {
0034         SMB21_PROT,
0035         "\2SMB 2.1",
0036         "SMB2_10",
0037         SMB21_PROT_ID
0038     },
0039     {
0040         SMB2X_PROT,
0041         "\2SMB 2.???",
0042         "SMB2_22",
0043         SMB2X_PROT_ID
0044     },
0045 };
0046 
0047 static struct smb_protocol smb2_protos[] = {
0048     {
0049         SMB21_PROT,
0050         "\2SMB 2.1",
0051         "SMB2_10",
0052         SMB21_PROT_ID
0053     },
0054     {
0055         SMB30_PROT,
0056         "\2SMB 3.0",
0057         "SMB3_00",
0058         SMB30_PROT_ID
0059     },
0060     {
0061         SMB302_PROT,
0062         "\2SMB 3.02",
0063         "SMB3_02",
0064         SMB302_PROT_ID
0065     },
0066     {
0067         SMB311_PROT,
0068         "\2SMB 3.1.1",
0069         "SMB3_11",
0070         SMB311_PROT_ID
0071     },
0072 };
0073 
0074 unsigned int ksmbd_server_side_copy_max_chunk_count(void)
0075 {
0076     return 256;
0077 }
0078 
0079 unsigned int ksmbd_server_side_copy_max_chunk_size(void)
0080 {
0081     return (2U << 30) - 1;
0082 }
0083 
0084 unsigned int ksmbd_server_side_copy_max_total_size(void)
0085 {
0086     return (2U << 30) - 1;
0087 }
0088 
0089 inline int ksmbd_min_protocol(void)
0090 {
0091     return SMB21_PROT;
0092 }
0093 
0094 inline int ksmbd_max_protocol(void)
0095 {
0096     return SMB311_PROT;
0097 }
0098 
0099 int ksmbd_lookup_protocol_idx(char *str)
0100 {
0101     int offt = ARRAY_SIZE(smb1_protos) - 1;
0102     int len = strlen(str);
0103 
0104     while (offt >= 0) {
0105         if (!strncmp(str, smb1_protos[offt].prot, len)) {
0106             ksmbd_debug(SMB, "selected %s dialect idx = %d\n",
0107                     smb1_protos[offt].prot, offt);
0108             return smb1_protos[offt].index;
0109         }
0110         offt--;
0111     }
0112 
0113     offt = ARRAY_SIZE(smb2_protos) - 1;
0114     while (offt >= 0) {
0115         if (!strncmp(str, smb2_protos[offt].prot, len)) {
0116             ksmbd_debug(SMB, "selected %s dialect idx = %d\n",
0117                     smb2_protos[offt].prot, offt);
0118             return smb2_protos[offt].index;
0119         }
0120         offt--;
0121     }
0122     return -1;
0123 }
0124 
0125 /**
0126  * ksmbd_verify_smb_message() - check for valid smb2 request header
0127  * @work:   smb work
0128  *
0129  * check for valid smb signature and packet direction(request/response)
0130  *
0131  * Return:      0 on success, otherwise -EINVAL
0132  */
0133 int ksmbd_verify_smb_message(struct ksmbd_work *work)
0134 {
0135     struct smb2_hdr *smb2_hdr = ksmbd_req_buf_next(work);
0136     struct smb_hdr *hdr;
0137 
0138     if (smb2_hdr->ProtocolId == SMB2_PROTO_NUMBER)
0139         return ksmbd_smb2_check_message(work);
0140 
0141     hdr = work->request_buf;
0142     if (*(__le32 *)hdr->Protocol == SMB1_PROTO_NUMBER &&
0143         hdr->Command == SMB_COM_NEGOTIATE) {
0144         work->conn->outstanding_credits++;
0145         return 0;
0146     }
0147 
0148     return -EINVAL;
0149 }
0150 
0151 /**
0152  * ksmbd_smb_request() - check for valid smb request type
0153  * @conn:   connection instance
0154  *
0155  * Return:      true on success, otherwise false
0156  */
0157 bool ksmbd_smb_request(struct ksmbd_conn *conn)
0158 {
0159     return conn->request_buf[0] == 0;
0160 }
0161 
0162 static bool supported_protocol(int idx)
0163 {
0164     if (idx == SMB2X_PROT &&
0165         (server_conf.min_protocol >= SMB21_PROT ||
0166          server_conf.max_protocol <= SMB311_PROT))
0167         return true;
0168 
0169     return (server_conf.min_protocol <= idx &&
0170         idx <= server_conf.max_protocol);
0171 }
0172 
0173 static char *next_dialect(char *dialect, int *next_off, int bcount)
0174 {
0175     dialect = dialect + *next_off;
0176     *next_off = strnlen(dialect, bcount);
0177     if (dialect[*next_off] != '\0')
0178         return NULL;
0179     return dialect;
0180 }
0181 
0182 static int ksmbd_lookup_dialect_by_name(char *cli_dialects, __le16 byte_count)
0183 {
0184     int i, seq_num, bcount, next;
0185     char *dialect;
0186 
0187     for (i = ARRAY_SIZE(smb1_protos) - 1; i >= 0; i--) {
0188         seq_num = 0;
0189         next = 0;
0190         dialect = cli_dialects;
0191         bcount = le16_to_cpu(byte_count);
0192         do {
0193             dialect = next_dialect(dialect, &next, bcount);
0194             if (!dialect)
0195                 break;
0196             ksmbd_debug(SMB, "client requested dialect %s\n",
0197                     dialect);
0198             if (!strcmp(dialect, smb1_protos[i].name)) {
0199                 if (supported_protocol(smb1_protos[i].index)) {
0200                     ksmbd_debug(SMB,
0201                             "selected %s dialect\n",
0202                             smb1_protos[i].name);
0203                     if (smb1_protos[i].index == SMB1_PROT)
0204                         return seq_num;
0205                     return smb1_protos[i].prot_id;
0206                 }
0207             }
0208             seq_num++;
0209             bcount -= (++next);
0210         } while (bcount > 0);
0211     }
0212 
0213     return BAD_PROT_ID;
0214 }
0215 
0216 int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count)
0217 {
0218     int i;
0219     int count;
0220 
0221     for (i = ARRAY_SIZE(smb2_protos) - 1; i >= 0; i--) {
0222         count = le16_to_cpu(dialects_count);
0223         while (--count >= 0) {
0224             ksmbd_debug(SMB, "client requested dialect 0x%x\n",
0225                     le16_to_cpu(cli_dialects[count]));
0226             if (le16_to_cpu(cli_dialects[count]) !=
0227                     smb2_protos[i].prot_id)
0228                 continue;
0229 
0230             if (supported_protocol(smb2_protos[i].index)) {
0231                 ksmbd_debug(SMB, "selected %s dialect\n",
0232                         smb2_protos[i].name);
0233                 return smb2_protos[i].prot_id;
0234             }
0235         }
0236     }
0237 
0238     return BAD_PROT_ID;
0239 }
0240 
0241 static int ksmbd_negotiate_smb_dialect(void *buf)
0242 {
0243     int smb_buf_length = get_rfc1002_len(buf);
0244     __le32 proto = ((struct smb2_hdr *)smb2_get_msg(buf))->ProtocolId;
0245 
0246     if (proto == SMB2_PROTO_NUMBER) {
0247         struct smb2_negotiate_req *req;
0248         int smb2_neg_size =
0249             offsetof(struct smb2_negotiate_req, Dialects);
0250 
0251         req = (struct smb2_negotiate_req *)smb2_get_msg(buf);
0252         if (smb2_neg_size > smb_buf_length)
0253             goto err_out;
0254 
0255         if (smb2_neg_size + le16_to_cpu(req->DialectCount) * sizeof(__le16) >
0256             smb_buf_length)
0257             goto err_out;
0258 
0259         return ksmbd_lookup_dialect_by_id(req->Dialects,
0260                           req->DialectCount);
0261     }
0262 
0263     proto = *(__le32 *)((struct smb_hdr *)buf)->Protocol;
0264     if (proto == SMB1_PROTO_NUMBER) {
0265         struct smb_negotiate_req *req;
0266 
0267         req = (struct smb_negotiate_req *)buf;
0268         if (le16_to_cpu(req->ByteCount) < 2)
0269             goto err_out;
0270 
0271         if (offsetof(struct smb_negotiate_req, DialectsArray) - 4 +
0272             le16_to_cpu(req->ByteCount) > smb_buf_length) {
0273             goto err_out;
0274         }
0275 
0276         return ksmbd_lookup_dialect_by_name(req->DialectsArray,
0277                             req->ByteCount);
0278     }
0279 
0280 err_out:
0281     return BAD_PROT_ID;
0282 }
0283 
0284 int ksmbd_init_smb_server(struct ksmbd_work *work)
0285 {
0286     struct ksmbd_conn *conn = work->conn;
0287 
0288     if (conn->need_neg == false)
0289         return 0;
0290 
0291     init_smb3_11_server(conn);
0292 
0293     if (conn->ops->get_cmd_val(work) != SMB_COM_NEGOTIATE)
0294         conn->need_neg = false;
0295     return 0;
0296 }
0297 
0298 int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level,
0299                       struct ksmbd_file *dir,
0300                       struct ksmbd_dir_info *d_info,
0301                       char *search_pattern,
0302                       int (*fn)(struct ksmbd_conn *, int,
0303                         struct ksmbd_dir_info *,
0304                         struct ksmbd_kstat *))
0305 {
0306     int i, rc = 0;
0307     struct ksmbd_conn *conn = work->conn;
0308     struct user_namespace *user_ns = file_mnt_user_ns(dir->filp);
0309 
0310     for (i = 0; i < 2; i++) {
0311         struct kstat kstat;
0312         struct ksmbd_kstat ksmbd_kstat;
0313         struct dentry *dentry;
0314 
0315         if (!dir->dot_dotdot[i]) { /* fill dot entry info */
0316             if (i == 0) {
0317                 d_info->name = ".";
0318                 d_info->name_len = 1;
0319                 dentry = dir->filp->f_path.dentry;
0320             } else {
0321                 d_info->name = "..";
0322                 d_info->name_len = 2;
0323                 dentry = dir->filp->f_path.dentry->d_parent;
0324             }
0325 
0326             if (!match_pattern(d_info->name, d_info->name_len,
0327                        search_pattern)) {
0328                 dir->dot_dotdot[i] = 1;
0329                 continue;
0330             }
0331 
0332             ksmbd_kstat.kstat = &kstat;
0333             ksmbd_vfs_fill_dentry_attrs(work,
0334                             user_ns,
0335                             dentry,
0336                             &ksmbd_kstat);
0337             rc = fn(conn, info_level, d_info, &ksmbd_kstat);
0338             if (rc)
0339                 break;
0340             if (d_info->out_buf_len <= 0)
0341                 break;
0342 
0343             dir->dot_dotdot[i] = 1;
0344             if (d_info->flags & SMB2_RETURN_SINGLE_ENTRY) {
0345                 d_info->out_buf_len = 0;
0346                 break;
0347             }
0348         }
0349     }
0350 
0351     return rc;
0352 }
0353 
0354 /**
0355  * ksmbd_extract_shortname() - get shortname from long filename
0356  * @conn:   connection instance
0357  * @longname:   source long filename
0358  * @shortname:  destination short filename
0359  *
0360  * Return:  shortname length or 0 when source long name is '.' or '..'
0361  * TODO: Though this function comforms the restriction of 8.3 Filename spec,
0362  * but the result is different with Windows 7's one. need to check.
0363  */
0364 int ksmbd_extract_shortname(struct ksmbd_conn *conn, const char *longname,
0365                 char *shortname)
0366 {
0367     const char *p;
0368     char base[9], extension[4];
0369     char out[13] = {0};
0370     int baselen = 0;
0371     int extlen = 0, len = 0;
0372     unsigned int csum = 0;
0373     const unsigned char *ptr;
0374     bool dot_present = true;
0375 
0376     p = longname;
0377     if ((*p == '.') || (!(strcmp(p, "..")))) {
0378         /*no mangling required */
0379         return 0;
0380     }
0381 
0382     p = strrchr(longname, '.');
0383     if (p == longname) { /*name starts with a dot*/
0384         strscpy(extension, "___", strlen("___"));
0385     } else {
0386         if (p) {
0387             p++;
0388             while (*p && extlen < 3) {
0389                 if (*p != '.')
0390                     extension[extlen++] = toupper(*p);
0391                 p++;
0392             }
0393             extension[extlen] = '\0';
0394         } else {
0395             dot_present = false;
0396         }
0397     }
0398 
0399     p = longname;
0400     if (*p == '.') {
0401         p++;
0402         longname++;
0403     }
0404     while (*p && (baselen < 5)) {
0405         if (*p != '.')
0406             base[baselen++] = toupper(*p);
0407         p++;
0408     }
0409 
0410     base[baselen] = MAGIC_CHAR;
0411     memcpy(out, base, baselen + 1);
0412 
0413     ptr = longname;
0414     len = strlen(longname);
0415     for (; len > 0; len--, ptr++)
0416         csum += *ptr;
0417 
0418     csum = csum % (MANGLE_BASE * MANGLE_BASE);
0419     out[baselen + 1] = mangle(csum / MANGLE_BASE);
0420     out[baselen + 2] = mangle(csum);
0421     out[baselen + 3] = PERIOD;
0422 
0423     if (dot_present)
0424         memcpy(&out[baselen + 4], extension, 4);
0425     else
0426         out[baselen + 4] = '\0';
0427     smbConvertToUTF16((__le16 *)shortname, out, PATH_MAX,
0428               conn->local_nls, 0);
0429     len = strlen(out) * 2;
0430     return len;
0431 }
0432 
0433 static int __smb2_negotiate(struct ksmbd_conn *conn)
0434 {
0435     return (conn->dialect >= SMB21_PROT_ID &&
0436         conn->dialect <= SMB311_PROT_ID);
0437 }
0438 
0439 static int smb_handle_negotiate(struct ksmbd_work *work)
0440 {
0441     struct smb_negotiate_rsp *neg_rsp = work->response_buf;
0442 
0443     ksmbd_debug(SMB, "Unsupported SMB protocol\n");
0444     neg_rsp->hdr.Status.CifsError = STATUS_INVALID_LOGON_TYPE;
0445     return -EINVAL;
0446 }
0447 
0448 int ksmbd_smb_negotiate_common(struct ksmbd_work *work, unsigned int command)
0449 {
0450     struct ksmbd_conn *conn = work->conn;
0451     int ret;
0452 
0453     conn->dialect =
0454         ksmbd_negotiate_smb_dialect(work->request_buf);
0455     ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect);
0456 
0457     if (command == SMB2_NEGOTIATE_HE) {
0458         struct smb2_hdr *smb2_hdr = smb2_get_msg(work->request_buf);
0459 
0460         if (smb2_hdr->ProtocolId != SMB2_PROTO_NUMBER) {
0461             ksmbd_debug(SMB, "Downgrade to SMB1 negotiation\n");
0462             command = SMB_COM_NEGOTIATE;
0463         }
0464     }
0465 
0466     if (command == SMB2_NEGOTIATE_HE && __smb2_negotiate(conn)) {
0467         ret = smb2_handle_negotiate(work);
0468         init_smb2_neg_rsp(work);
0469         return ret;
0470     }
0471 
0472     if (command == SMB_COM_NEGOTIATE) {
0473         if (__smb2_negotiate(conn)) {
0474             conn->need_neg = true;
0475             init_smb3_11_server(conn);
0476             init_smb2_neg_rsp(work);
0477             ksmbd_debug(SMB, "Upgrade to SMB2 negotiation\n");
0478             return 0;
0479         }
0480         return smb_handle_negotiate(work);
0481     }
0482 
0483     pr_err("Unknown SMB negotiation command: %u\n", command);
0484     return -EINVAL;
0485 }
0486 
0487 enum SHARED_MODE_ERRORS {
0488     SHARE_DELETE_ERROR,
0489     SHARE_READ_ERROR,
0490     SHARE_WRITE_ERROR,
0491     FILE_READ_ERROR,
0492     FILE_WRITE_ERROR,
0493     FILE_DELETE_ERROR,
0494 };
0495 
0496 static const char * const shared_mode_errors[] = {
0497     "Current access mode does not permit SHARE_DELETE",
0498     "Current access mode does not permit SHARE_READ",
0499     "Current access mode does not permit SHARE_WRITE",
0500     "Desired access mode does not permit FILE_READ",
0501     "Desired access mode does not permit FILE_WRITE",
0502     "Desired access mode does not permit FILE_DELETE",
0503 };
0504 
0505 static void smb_shared_mode_error(int error, struct ksmbd_file *prev_fp,
0506                   struct ksmbd_file *curr_fp)
0507 {
0508     ksmbd_debug(SMB, "%s\n", shared_mode_errors[error]);
0509     ksmbd_debug(SMB, "Current mode: 0x%x Desired mode: 0x%x\n",
0510             prev_fp->saccess, curr_fp->daccess);
0511 }
0512 
0513 int ksmbd_smb_check_shared_mode(struct file *filp, struct ksmbd_file *curr_fp)
0514 {
0515     int rc = 0;
0516     struct ksmbd_file *prev_fp;
0517 
0518     /*
0519      * Lookup fp in master fp list, and check desired access and
0520      * shared mode between previous open and current open.
0521      */
0522     read_lock(&curr_fp->f_ci->m_lock);
0523     list_for_each_entry(prev_fp, &curr_fp->f_ci->m_fp_list, node) {
0524         if (file_inode(filp) != file_inode(prev_fp->filp))
0525             continue;
0526 
0527         if (filp == prev_fp->filp)
0528             continue;
0529 
0530         if (ksmbd_stream_fd(prev_fp) && ksmbd_stream_fd(curr_fp))
0531             if (strcmp(prev_fp->stream.name, curr_fp->stream.name))
0532                 continue;
0533 
0534         if (prev_fp->attrib_only != curr_fp->attrib_only)
0535             continue;
0536 
0537         if (!(prev_fp->saccess & FILE_SHARE_DELETE_LE) &&
0538             curr_fp->daccess & FILE_DELETE_LE) {
0539             smb_shared_mode_error(SHARE_DELETE_ERROR,
0540                           prev_fp,
0541                           curr_fp);
0542             rc = -EPERM;
0543             break;
0544         }
0545 
0546         /*
0547          * Only check FILE_SHARE_DELETE if stream opened and
0548          * normal file opened.
0549          */
0550         if (ksmbd_stream_fd(prev_fp) && !ksmbd_stream_fd(curr_fp))
0551             continue;
0552 
0553         if (!(prev_fp->saccess & FILE_SHARE_READ_LE) &&
0554             curr_fp->daccess & (FILE_EXECUTE_LE | FILE_READ_DATA_LE)) {
0555             smb_shared_mode_error(SHARE_READ_ERROR,
0556                           prev_fp,
0557                           curr_fp);
0558             rc = -EPERM;
0559             break;
0560         }
0561 
0562         if (!(prev_fp->saccess & FILE_SHARE_WRITE_LE) &&
0563             curr_fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE)) {
0564             smb_shared_mode_error(SHARE_WRITE_ERROR,
0565                           prev_fp,
0566                           curr_fp);
0567             rc = -EPERM;
0568             break;
0569         }
0570 
0571         if (prev_fp->daccess & (FILE_EXECUTE_LE | FILE_READ_DATA_LE) &&
0572             !(curr_fp->saccess & FILE_SHARE_READ_LE)) {
0573             smb_shared_mode_error(FILE_READ_ERROR,
0574                           prev_fp,
0575                           curr_fp);
0576             rc = -EPERM;
0577             break;
0578         }
0579 
0580         if (prev_fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE) &&
0581             !(curr_fp->saccess & FILE_SHARE_WRITE_LE)) {
0582             smb_shared_mode_error(FILE_WRITE_ERROR,
0583                           prev_fp,
0584                           curr_fp);
0585             rc = -EPERM;
0586             break;
0587         }
0588 
0589         if (prev_fp->daccess & FILE_DELETE_LE &&
0590             !(curr_fp->saccess & FILE_SHARE_DELETE_LE)) {
0591             smb_shared_mode_error(FILE_DELETE_ERROR,
0592                           prev_fp,
0593                           curr_fp);
0594             rc = -EPERM;
0595             break;
0596         }
0597     }
0598     read_unlock(&curr_fp->f_ci->m_lock);
0599 
0600     return rc;
0601 }
0602 
0603 bool is_asterisk(char *p)
0604 {
0605     return p && p[0] == '*';
0606 }
0607 
0608 int ksmbd_override_fsids(struct ksmbd_work *work)
0609 {
0610     struct ksmbd_session *sess = work->sess;
0611     struct ksmbd_share_config *share = work->tcon->share_conf;
0612     struct cred *cred;
0613     struct group_info *gi;
0614     unsigned int uid;
0615     unsigned int gid;
0616 
0617     uid = user_uid(sess->user);
0618     gid = user_gid(sess->user);
0619     if (share->force_uid != KSMBD_SHARE_INVALID_UID)
0620         uid = share->force_uid;
0621     if (share->force_gid != KSMBD_SHARE_INVALID_GID)
0622         gid = share->force_gid;
0623 
0624     cred = prepare_kernel_cred(NULL);
0625     if (!cred)
0626         return -ENOMEM;
0627 
0628     cred->fsuid = make_kuid(current_user_ns(), uid);
0629     cred->fsgid = make_kgid(current_user_ns(), gid);
0630 
0631     gi = groups_alloc(0);
0632     if (!gi) {
0633         abort_creds(cred);
0634         return -ENOMEM;
0635     }
0636     set_groups(cred, gi);
0637     put_group_info(gi);
0638 
0639     if (!uid_eq(cred->fsuid, GLOBAL_ROOT_UID))
0640         cred->cap_effective = cap_drop_fs_set(cred->cap_effective);
0641 
0642     WARN_ON(work->saved_cred);
0643     work->saved_cred = override_creds(cred);
0644     if (!work->saved_cred) {
0645         abort_creds(cred);
0646         return -EINVAL;
0647     }
0648     return 0;
0649 }
0650 
0651 void ksmbd_revert_fsids(struct ksmbd_work *work)
0652 {
0653     const struct cred *cred;
0654 
0655     WARN_ON(!work->saved_cred);
0656 
0657     cred = current_cred();
0658     revert_creds(work->saved_cred);
0659     put_cred(cred);
0660     work->saved_cred = NULL;
0661 }
0662 
0663 __le32 smb_map_generic_desired_access(__le32 daccess)
0664 {
0665     if (daccess & FILE_GENERIC_READ_LE) {
0666         daccess |= cpu_to_le32(GENERIC_READ_FLAGS);
0667         daccess &= ~FILE_GENERIC_READ_LE;
0668     }
0669 
0670     if (daccess & FILE_GENERIC_WRITE_LE) {
0671         daccess |= cpu_to_le32(GENERIC_WRITE_FLAGS);
0672         daccess &= ~FILE_GENERIC_WRITE_LE;
0673     }
0674 
0675     if (daccess & FILE_GENERIC_EXECUTE_LE) {
0676         daccess |= cpu_to_le32(GENERIC_EXECUTE_FLAGS);
0677         daccess &= ~FILE_GENERIC_EXECUTE_LE;
0678     }
0679 
0680     if (daccess & FILE_GENERIC_ALL_LE) {
0681         daccess |= cpu_to_le32(GENERIC_ALL_FLAGS);
0682         daccess &= ~FILE_GENERIC_ALL_LE;
0683     }
0684 
0685     return daccess;
0686 }