1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * linux/fs/lockd/svcshare.c 4 * 5 * Management of DOS shares. 6 * 7 * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de> 8 */ 9 10 #include <linux/time.h> 11 #include <linux/unistd.h> 12 #include <linux/string.h> 13 #include <linux/slab.h> 14 15 #include <linux/sunrpc/clnt.h> 16 #include <linux/sunrpc/svc.h> 17 18 #include "lockd.h" 19 #include "share.h" 20 21 static inline int 22 nlm_cmp_owner(struct lockd_share *share, struct xdr_netobj *oh) 23 { 24 return share->s_owner.len == oh->len 25 && !memcmp(share->s_owner.data, oh->data, oh->len); 26 } 27 28 /* 29 * Recompute s_access / s_mode as the union of every (access, deny) pair 30 * whose bit is currently set in s_access_deny_bmap. 31 */ 32 static void nlm_recompute_share(struct lockd_share *share) 33 { 34 u32 new_access = 0, new_mode = 0; 35 unsigned int i; 36 37 for (i = 0; i < 16; i++) { 38 if (share->s_access_deny_bmap & BIT(i)) { 39 new_access |= i >> 2; 40 new_mode |= i & 3; 41 } 42 } 43 share->s_access = new_access; 44 share->s_mode = new_mode; 45 } 46 47 /** 48 * nlmsvc_share_file - create a share 49 * @host: Network client peer 50 * @file: File to be shared 51 * @oh: Share owner handle 52 * @access: Requested access mode 53 * @mode: Requested file sharing mode 54 * 55 * Returns an NLM status code. 56 */ 57 __be32 58 nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file, 59 struct xdr_netobj *oh, u32 access, u32 mode) 60 { 61 struct lockd_share *share; 62 u8 *ohdata; 63 64 if (nlmsvc_file_cannot_lock(file)) 65 return nlm_lck_denied_nolocks; 66 67 for (share = file->f_shares; share; share = share->s_next) { 68 if (share->s_host == host && nlm_cmp_owner(share, oh)) 69 goto update; 70 if ((access & share->s_mode) || (mode & share->s_access)) 71 return nlm_lck_denied; 72 } 73 74 share = kmalloc(sizeof(*share) + oh->len, GFP_KERNEL); 75 if (share == NULL) 76 return nlm_lck_denied_nolocks; 77 78 /* Copy owner handle */ 79 ohdata = (u8 *) (share + 1); 80 memcpy(ohdata, oh->data, oh->len); 81 82 share->s_file = file; 83 share->s_host = host; 84 share->s_owner.data = ohdata; 85 share->s_owner.len = oh->len; 86 share->s_access_deny_bmap = 0; 87 share->s_next = file->f_shares; 88 file->f_shares = share; 89 90 update: 91 share->s_access_deny_bmap |= LOCKD_FSH_BIT(access, mode); 92 nlm_recompute_share(share); 93 return nlm_granted; 94 } 95 96 /** 97 * nlmsvc_unshare_file - delete a share 98 * @host: Network client peer 99 * @file: File to be unshared 100 * @oh: Share owner handle 101 * @access: Access mode of the SHARE being released 102 * @mode: Deny mode of the SHARE being released 103 * 104 * Returns an NLM status code. 105 */ 106 __be32 107 nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file, 108 struct xdr_netobj *oh, u32 access, u32 mode) 109 { 110 struct lockd_share *share, **shpp; 111 112 if (nlmsvc_file_cannot_lock(file)) 113 return nlm_lck_denied_nolocks; 114 115 for (shpp = &file->f_shares; (share = *shpp) != NULL; 116 shpp = &share->s_next) { 117 if (share->s_host == host && nlm_cmp_owner(share, oh)) { 118 share->s_access_deny_bmap &= ~LOCKD_FSH_BIT(access, mode); 119 nlm_recompute_share(share); 120 if (!share->s_access_deny_bmap) { 121 *shpp = share->s_next; 122 kfree(share); 123 } 124 return nlm_granted; 125 } 126 } 127 128 /* X/Open spec says return success even if there was no 129 * corresponding share. */ 130 return nlm_granted; 131 } 132 133 /* 134 * Traverse all shares for a given file, and delete 135 * those owned by the given (type of) host 136 */ 137 void nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, 138 nlm_host_match_fn_t match) 139 { 140 struct lockd_share *share, **shpp; 141 142 shpp = &file->f_shares; 143 while ((share = *shpp) != NULL) { 144 if (match(share->s_host, host)) { 145 *shpp = share->s_next; 146 kfree(share); 147 continue; 148 } 149 shpp = &share->s_next; 150 } 151 } 152