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 nlm_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 * nlmsvc_share_file - create a share 30 * @host: Network client peer 31 * @file: File to be shared 32 * @oh: Share owner handle 33 * @access: Requested access mode 34 * @mode: Requested file sharing mode 35 * 36 * Returns an NLM status code. 37 */ 38 __be32 39 nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file, 40 struct xdr_netobj *oh, u32 access, u32 mode) 41 { 42 struct nlm_share *share; 43 u8 *ohdata; 44 45 if (nlmsvc_file_cannot_lock(file)) 46 return nlm_lck_denied_nolocks; 47 48 for (share = file->f_shares; share; share = share->s_next) { 49 if (share->s_host == host && nlm_cmp_owner(share, oh)) 50 goto update; 51 if ((access & share->s_mode) || (mode & share->s_access)) 52 return nlm_lck_denied; 53 } 54 55 share = kmalloc(sizeof(*share) + oh->len, GFP_KERNEL); 56 if (share == NULL) 57 return nlm_lck_denied_nolocks; 58 59 /* Copy owner handle */ 60 ohdata = (u8 *) (share + 1); 61 memcpy(ohdata, oh->data, oh->len); 62 63 share->s_file = file; 64 share->s_host = host; 65 share->s_owner.data = ohdata; 66 share->s_owner.len = oh->len; 67 share->s_next = file->f_shares; 68 file->f_shares = share; 69 70 update: 71 share->s_access = access; 72 share->s_mode = mode; 73 return nlm_granted; 74 } 75 76 /** 77 * nlmsvc_unshare_file - delete a share 78 * @host: Network client peer 79 * @file: File to be unshared 80 * @oh: Share owner handle 81 * 82 * Returns an NLM status code. 83 */ 84 __be32 85 nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file, 86 struct xdr_netobj *oh) 87 { 88 struct nlm_share *share, **shpp; 89 90 if (nlmsvc_file_cannot_lock(file)) 91 return nlm_lck_denied_nolocks; 92 93 for (shpp = &file->f_shares; (share = *shpp) != NULL; 94 shpp = &share->s_next) { 95 if (share->s_host == host && nlm_cmp_owner(share, oh)) { 96 *shpp = share->s_next; 97 kfree(share); 98 return nlm_granted; 99 } 100 } 101 102 /* X/Open spec says return success even if there was no 103 * corresponding share. */ 104 return nlm_granted; 105 } 106 107 /* 108 * Traverse all shares for a given file, and delete 109 * those owned by the given (type of) host 110 */ 111 void nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, 112 nlm_host_match_fn_t match) 113 { 114 struct nlm_share *share, **shpp; 115 116 shpp = &file->f_shares; 117 while ((share = *shpp) != NULL) { 118 if (match(share->s_host, host)) { 119 *shpp = share->s_next; 120 kfree(share); 121 continue; 122 } 123 shpp = &share->s_next; 124 } 125 } 126