Deleted Added
sdiff udiff text old ( 275941 ) new ( 291527 )
full compact
1/*-
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without

--- 18 unchanged lines hidden (view full) ---

27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: head/sys/fs/nfs/nfs_commonsubs.c 291527 2015-11-30 21:54:27Z rmacklem $");
36
37/*
38 * These functions support the macros and help fiddle mbuf chains for
39 * the nfs op functions. They do things like create the rpc header and
40 * copy data between mbuf chains and uio lists.
41 */
42#ifndef APPLEKEXT
43#include "opt_inet6.h"
44
45#include <fs/nfs/nfsport.h>
46
47#include <security/mac/mac_framework.h>
48
49/*
50 * Data items converted to xdr at startup, since they are constant
51 * This is kinda hokey, but may save a little time doing byte swaps
52 */
53u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
54
55/* And other global data */
56nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,

--- 8 unchanged lines hidden (view full) ---

65struct nfsreqhead nfsd_reqq;
66uid_t nfsrv_defaultuid;
67gid_t nfsrv_defaultgid;
68int nfsrv_lease = NFSRV_LEASE;
69int ncl_mbuf_mlen = MLEN;
70int nfsd_enable_stringtouid = 0;
71NFSNAMEIDMUTEX;
72NFSSOCKMUTEX;
73extern int nfsrv_lughashsize;
74
75/*
76 * This array of structures indicates, for V4:
77 * retfh - which of 3 types of calling args are used
78 * 0 - doesn't change cfh or use a sfh
79 * 1 - replaces cfh with a new one (unless it returns an error status)
80 * 2 - uses cfh and sfh
81 * needscfh - if the op wants a cfh and premtime

--- 70 unchanged lines hidden (view full) ---

152};
153#endif /* !APPLEKEXT */
154
155static int ncl_mbuf_mhlen = MHLEN;
156static int nfsrv_usercnt = 0;
157static int nfsrv_dnsnamelen;
158static u_char *nfsrv_dnsname = NULL;
159static int nfsrv_usermax = 999999999;
160struct nfsrv_lughash {
161 struct mtx mtx;
162 struct nfsuserhashhead lughead;
163};
164static struct nfsrv_lughash *nfsuserhash;
165static struct nfsrv_lughash *nfsusernamehash;
166static struct nfsrv_lughash *nfsgrouphash;
167static struct nfsrv_lughash *nfsgroupnamehash;
168
169/*
170 * This static array indicates whether or not the RPC generates a large
171 * reply. This is used by nfs_reply() to decide whether or not an mbuf
172 * cluster should be allocated. (If a cluster is required by an RPC
173 * marked 0 in this array, the code will still work, just not quite as
174 * efficiently.)
175 */
176int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
177 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
178 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
179
180/* local functions */
181static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
182static void nfsv4_wanted(struct nfsv4lock *lp);
183static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
184static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
185 NFSPROC_T *p);
186static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
187static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
188 int *, int *);
189static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
190
191
192#ifndef APPLE
193/*
194 * copies mbuf chain to the uio scatter/gather list

--- 2354 unchanged lines hidden (view full) ---

2549APPLESTATIC void
2550nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2551{
2552 int i;
2553 struct nfsusrgrp *usrp;
2554 u_char *cp = *cpp;
2555 uid_t tmp;
2556 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2557 struct nfsrv_lughash *hp;
2558
2559 cnt = 0;
2560tryagain:
2561 if (nfsrv_dnsnamelen > 0) {
2562 /*
2563 * Always map nfsrv_defaultuid to "nobody".
2564 */
2565 if (uid == nfsrv_defaultuid) {
2566 i = nfsrv_dnsnamelen + 7;
2567 if (i > len) {
2568 if (len > NFSV4_SMALLSTR)
2569 free(cp, M_NFSSTRING);
2570 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2571 *cpp = cp;
2572 len = i;
2573 goto tryagain;
2574 }
2575 *retlenp = i;
2576 NFSBCOPY("nobody@", cp, 7);
2577 cp += 7;
2578 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2579 return;
2580 }
2581 hasampersand = 0;
2582 hp = NFSUSERHASH(uid);
2583 mtx_lock(&hp->mtx);
2584 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2585 if (usrp->lug_uid == uid) {
2586 if (usrp->lug_expiry < NFSD_MONOSEC)
2587 break;
2588 /*
2589 * If the name doesn't already have an '@'
2590 * in it, append @domainname to it.
2591 */
2592 for (i = 0; i < usrp->lug_namelen; i++) {
2593 if (usrp->lug_name[i] == '@') {
2594 hasampersand = 1;
2595 break;
2596 }
2597 }
2598 if (hasampersand)
2599 i = usrp->lug_namelen;
2600 else
2601 i = usrp->lug_namelen +
2602 nfsrv_dnsnamelen + 1;
2603 if (i > len) {
2604 mtx_unlock(&hp->mtx);
2605 if (len > NFSV4_SMALLSTR)
2606 free(cp, M_NFSSTRING);
2607 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2608 *cpp = cp;
2609 len = i;
2610 goto tryagain;
2611 }
2612 *retlenp = i;
2613 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2614 if (!hasampersand) {
2615 cp += usrp->lug_namelen;
2616 *cp++ = '@';
2617 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2618 }
2619 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2620 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2621 lug_numhash);
2622 mtx_unlock(&hp->mtx);
2623 return;
2624 }
2625 }
2626 mtx_unlock(&hp->mtx);
2627 cnt++;
2628 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2629 NULL, p);
2630 if (ret == 0 && cnt < 2)
2631 goto tryagain;
2632 }
2633
2634 /*
2635 * No match, just return a string of digits.
2636 */
2637 tmp = uid;
2638 i = 0;
2639 while (tmp || i == 0) {

--- 7 unchanged lines hidden (view full) ---

2647 for (i = 0; i < len; i++) {
2648 *cp-- = '0' + (tmp % 10);
2649 tmp /= 10;
2650 }
2651 return;
2652}
2653
2654/*
2655 * Get a credential for the uid with the server's group list.
2656 * If none is found, just return the credential passed in after
2657 * logging a warning message.
2658 */
2659struct ucred *
2660nfsrv_getgrpscred(struct ucred *oldcred)
2661{
2662 struct nfsusrgrp *usrp;
2663 struct ucred *newcred;
2664 int cnt, ret;
2665 uid_t uid;
2666 struct nfsrv_lughash *hp;
2667
2668 cnt = 0;
2669 uid = oldcred->cr_uid;
2670tryagain:
2671 if (nfsrv_dnsnamelen > 0) {
2672 hp = NFSUSERHASH(uid);
2673 mtx_lock(&hp->mtx);
2674 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2675 if (usrp->lug_uid == uid) {
2676 if (usrp->lug_expiry < NFSD_MONOSEC)
2677 break;
2678 if (usrp->lug_cred != NULL) {
2679 newcred = crhold(usrp->lug_cred);
2680 crfree(oldcred);
2681 } else
2682 newcred = oldcred;
2683 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2684 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2685 lug_numhash);
2686 mtx_unlock(&hp->mtx);
2687 return (newcred);
2688 }
2689 }
2690 mtx_unlock(&hp->mtx);
2691 cnt++;
2692 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2693 NULL, curthread);
2694 if (ret == 0 && cnt < 2)
2695 goto tryagain;
2696 }
2697 return (oldcred);
2698}
2699
2700/*
2701 * Convert a string to a uid.
2702 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2703 * return 0.
2704 * If this is called from a client side mount using AUTH_SYS and the
2705 * string is made up entirely of digits, just convert the string to
2706 * a number.
2707 */
2708APPLESTATIC int
2709nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2710 NFSPROC_T *p)
2711{
2712 int i;
2713 char *cp, *endstr, *str0;
2714 struct nfsusrgrp *usrp;
2715 int cnt, ret;
2716 int error = 0;
2717 uid_t tuid;
2718 struct nfsrv_lughash *hp, *hp2;
2719
2720 if (len == 0) {
2721 error = NFSERR_BADOWNER;
2722 goto out;
2723 }
2724 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2725 str0 = str;
2726 tuid = (uid_t)strtoul(str0, &endstr, 10);

--- 13 unchanged lines hidden (view full) ---

2740 cp = strchr(str0, '@');
2741 if (cp != NULL)
2742 i = (int)(cp++ - str0);
2743 else
2744 i = len;
2745
2746 cnt = 0;
2747tryagain:
2748 if (nfsrv_dnsnamelen > 0) {
2749 /*
2750 * If an '@' is found and the domain name matches, search for
2751 * the name with dns stripped off.
2752 * Mixed case alpahbetics will match for the domain name, but
2753 * all upper case will not.
2754 */
2755 if (cnt == 0 && i < len && i > 0 &&
2756 (len - 1 - i) == nfsrv_dnsnamelen &&
2757 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2758 len -= (nfsrv_dnsnamelen + 1);
2759 *(cp - 1) = '\0';
2760 }
2761
2762 /*
2763 * Check for the special case of "nobody".
2764 */
2765 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2766 *uidp = nfsrv_defaultuid;
2767 error = 0;
2768 goto out;
2769 }
2770
2771 hp = NFSUSERNAMEHASH(str, len);
2772 mtx_lock(&hp->mtx);
2773 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2774 if (usrp->lug_namelen == len &&
2775 !NFSBCMP(usrp->lug_name, str, len)) {
2776 if (usrp->lug_expiry < NFSD_MONOSEC)
2777 break;
2778 hp2 = NFSUSERHASH(usrp->lug_uid);
2779 mtx_lock(&hp2->mtx);
2780 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2781 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2782 lug_numhash);
2783 *uidp = usrp->lug_uid;
2784 mtx_unlock(&hp2->mtx);
2785 mtx_unlock(&hp->mtx);
2786 error = 0;
2787 goto out;
2788 }
2789 }
2790 mtx_unlock(&hp->mtx);
2791 cnt++;
2792 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2793 str, p);
2794 if (ret == 0 && cnt < 2)
2795 goto tryagain;
2796 }
2797 error = NFSERR_BADOWNER;
2798
2799out:
2800 NFSEXITCODE(error);
2801 return (error);
2802}
2803
2804/*

--- 6 unchanged lines hidden (view full) ---

2811APPLESTATIC void
2812nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2813{
2814 int i;
2815 struct nfsusrgrp *usrp;
2816 u_char *cp = *cpp;
2817 gid_t tmp;
2818 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2819 struct nfsrv_lughash *hp;
2820
2821 cnt = 0;
2822tryagain:
2823 if (nfsrv_dnsnamelen > 0) {
2824 /*
2825 * Always map nfsrv_defaultgid to "nogroup".
2826 */
2827 if (gid == nfsrv_defaultgid) {
2828 i = nfsrv_dnsnamelen + 8;
2829 if (i > len) {
2830 if (len > NFSV4_SMALLSTR)
2831 free(cp, M_NFSSTRING);
2832 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2833 *cpp = cp;
2834 len = i;
2835 goto tryagain;
2836 }
2837 *retlenp = i;
2838 NFSBCOPY("nogroup@", cp, 8);
2839 cp += 8;
2840 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2841 return;
2842 }
2843 hasampersand = 0;
2844 hp = NFSGROUPHASH(gid);
2845 mtx_lock(&hp->mtx);
2846 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
2847 if (usrp->lug_gid == gid) {
2848 if (usrp->lug_expiry < NFSD_MONOSEC)
2849 break;
2850 /*
2851 * If the name doesn't already have an '@'
2852 * in it, append @domainname to it.
2853 */
2854 for (i = 0; i < usrp->lug_namelen; i++) {
2855 if (usrp->lug_name[i] == '@') {
2856 hasampersand = 1;
2857 break;
2858 }
2859 }
2860 if (hasampersand)
2861 i = usrp->lug_namelen;
2862 else
2863 i = usrp->lug_namelen +
2864 nfsrv_dnsnamelen + 1;
2865 if (i > len) {
2866 mtx_unlock(&hp->mtx);
2867 if (len > NFSV4_SMALLSTR)
2868 free(cp, M_NFSSTRING);
2869 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2870 *cpp = cp;
2871 len = i;
2872 goto tryagain;
2873 }
2874 *retlenp = i;
2875 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2876 if (!hasampersand) {
2877 cp += usrp->lug_namelen;
2878 *cp++ = '@';
2879 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2880 }
2881 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
2882 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
2883 lug_numhash);
2884 mtx_unlock(&hp->mtx);
2885 return;
2886 }
2887 }
2888 mtx_unlock(&hp->mtx);
2889 cnt++;
2890 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2891 NULL, p);
2892 if (ret == 0 && cnt < 2)
2893 goto tryagain;
2894 }
2895
2896 /*
2897 * No match, just return a string of digits.
2898 */
2899 tmp = gid;
2900 i = 0;
2901 while (tmp || i == 0) {

--- 24 unchanged lines hidden (view full) ---

2926 NFSPROC_T *p)
2927{
2928 int i;
2929 char *cp, *endstr, *str0;
2930 struct nfsusrgrp *usrp;
2931 int cnt, ret;
2932 int error = 0;
2933 gid_t tgid;
2934 struct nfsrv_lughash *hp, *hp2;
2935
2936 if (len == 0) {
2937 error = NFSERR_BADOWNER;
2938 goto out;
2939 }
2940 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2941 str0 = str;
2942 tgid = (gid_t)strtoul(str0, &endstr, 10);

--- 13 unchanged lines hidden (view full) ---

2956 cp = strchr(str0, '@');
2957 if (cp != NULL)
2958 i = (int)(cp++ - str0);
2959 else
2960 i = len;
2961
2962 cnt = 0;
2963tryagain:
2964 if (nfsrv_dnsnamelen > 0) {
2965 /*
2966 * If an '@' is found and the dns name matches, search for the
2967 * name with the dns stripped off.
2968 */
2969 if (cnt == 0 && i < len && i > 0 &&
2970 (len - 1 - i) == nfsrv_dnsnamelen &&
2971 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2972 len -= (nfsrv_dnsnamelen + 1);
2973 *(cp - 1) = '\0';
2974 }
2975
2976 /*
2977 * Check for the special case of "nogroup".
2978 */
2979 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2980 *gidp = nfsrv_defaultgid;
2981 error = 0;
2982 goto out;
2983 }
2984
2985 hp = NFSGROUPNAMEHASH(str, len);
2986 mtx_lock(&hp->mtx);
2987 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
2988 if (usrp->lug_namelen == len &&
2989 !NFSBCMP(usrp->lug_name, str, len)) {
2990 if (usrp->lug_expiry < NFSD_MONOSEC)
2991 break;
2992 hp2 = NFSGROUPHASH(usrp->lug_gid);
2993 mtx_lock(&hp2->mtx);
2994 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
2995 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
2996 lug_numhash);
2997 *gidp = usrp->lug_gid;
2998 mtx_unlock(&hp2->mtx);
2999 mtx_unlock(&hp->mtx);
3000 error = 0;
3001 goto out;
3002 }
3003 }
3004 mtx_unlock(&hp->mtx);
3005 cnt++;
3006 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3007 str, p);
3008 if (ret == 0 && cnt < 2)
3009 goto tryagain;
3010 }
3011 error = NFSERR_BADOWNER;
3012
3013out:
3014 NFSEXITCODE(error);
3015 return (error);
3016}
3017
3018/*

--- 141 unchanged lines hidden (view full) ---

3160/*
3161 * This function is called from the nfssvc(2) system call, to update the
3162 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3163 */
3164APPLESTATIC int
3165nfssvc_idname(struct nfsd_idargs *nidp)
3166{
3167 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3168 struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3169 int i, group_locked, groupname_locked, user_locked, username_locked;
3170 int error = 0;
3171 u_char *cp;
3172 gid_t *grps;
3173 struct ucred *cr;
3174 static int onethread = 0;
3175 static time_t lasttime = 0;
3176
3177 if (nidp->nid_flag & NFSID_INITIALIZE) {
3178 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3179 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3180 nidp->nid_namelen);
3181 if (error != 0) {
3182 free(cp, M_NFSSTRING);
3183 goto out;
3184 }
3185 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3186 /*
3187 * Free up all the old stuff and reinitialize hash
3188 * lists. All mutexes for both lists must be locked,
3189 * with the user/group name ones before the uid/gid
3190 * ones, to avoid a LOR.
3191 */
3192 for (i = 0; i < nfsrv_lughashsize; i++)
3193 mtx_lock(&nfsusernamehash[i].mtx);
3194 for (i = 0; i < nfsrv_lughashsize; i++)
3195 mtx_lock(&nfsuserhash[i].mtx);
3196 for (i = 0; i < nfsrv_lughashsize; i++)
3197 TAILQ_FOREACH_SAFE(usrp,
3198 &nfsuserhash[i].lughead, lug_numhash, nusrp)
3199 nfsrv_removeuser(usrp, 1);
3200 for (i = 0; i < nfsrv_lughashsize; i++)
3201 mtx_unlock(&nfsuserhash[i].mtx);
3202 for (i = 0; i < nfsrv_lughashsize; i++)
3203 mtx_unlock(&nfsusernamehash[i].mtx);
3204 for (i = 0; i < nfsrv_lughashsize; i++)
3205 mtx_lock(&nfsgroupnamehash[i].mtx);
3206 for (i = 0; i < nfsrv_lughashsize; i++)
3207 mtx_lock(&nfsgrouphash[i].mtx);
3208 for (i = 0; i < nfsrv_lughashsize; i++)
3209 TAILQ_FOREACH_SAFE(usrp,
3210 &nfsgrouphash[i].lughead, lug_numhash,
3211 nusrp)
3212 nfsrv_removeuser(usrp, 0);
3213 for (i = 0; i < nfsrv_lughashsize; i++)
3214 mtx_unlock(&nfsgrouphash[i].mtx);
3215 for (i = 0; i < nfsrv_lughashsize; i++)
3216 mtx_unlock(&nfsgroupnamehash[i].mtx);
3217 free(nfsrv_dnsname, M_NFSSTRING);
3218 nfsrv_dnsname = NULL;
3219 }
3220 if (nfsuserhash == NULL) {
3221 /* Allocate the hash tables. */
3222 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3223 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3224 M_ZERO);
3225 for (i = 0; i < nfsrv_lughashsize; i++)
3226 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3227 NULL, MTX_DEF | MTX_DUPOK);
3228 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3229 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3230 M_ZERO);
3231 for (i = 0; i < nfsrv_lughashsize; i++)
3232 mtx_init(&nfsusernamehash[i].mtx,
3233 "nfsusrhash", NULL, MTX_DEF |
3234 MTX_DUPOK);
3235 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3236 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3237 M_ZERO);
3238 for (i = 0; i < nfsrv_lughashsize; i++)
3239 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3240 NULL, MTX_DEF | MTX_DUPOK);
3241 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3242 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3243 M_ZERO);
3244 for (i = 0; i < nfsrv_lughashsize; i++)
3245 mtx_init(&nfsgroupnamehash[i].mtx,
3246 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3247 }
3248 /* (Re)initialize the list heads. */
3249 for (i = 0; i < nfsrv_lughashsize; i++)
3250 TAILQ_INIT(&nfsuserhash[i].lughead);
3251 for (i = 0; i < nfsrv_lughashsize; i++)
3252 TAILQ_INIT(&nfsusernamehash[i].lughead);
3253 for (i = 0; i < nfsrv_lughashsize; i++)
3254 TAILQ_INIT(&nfsgrouphash[i].lughead);
3255 for (i = 0; i < nfsrv_lughashsize; i++)
3256 TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3257
3258 /*
3259 * Put name in "DNS" string.
3260 */
3261 nfsrv_dnsname = cp;
3262 nfsrv_defaultuid = nidp->nid_uid;
3263 nfsrv_defaultgid = nidp->nid_gid;
3264 nfsrv_usercnt = 0;
3265 nfsrv_usermax = nidp->nid_usermax;
3266 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3267 goto out;
3268 }
3269
3270 /*
3271 * malloc the new one now, so any potential sleep occurs before
3272 * manipulation of the lists.
3273 */
3274 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3275 M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3276 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3277 nidp->nid_namelen);
3278 if (error == 0 && nidp->nid_ngroup > 0 &&
3279 (nidp->nid_flag & NFSID_ADDUID) != 0) {
3280 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3281 M_WAITOK);
3282 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3283 sizeof(gid_t) * nidp->nid_ngroup);
3284 if (error == 0) {
3285 /*
3286 * Create a credential just like svc_getcred(),
3287 * but using the group list provided.
3288 */
3289 cr = crget();
3290 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3291 crsetgroups(cr, nidp->nid_ngroup, grps);
3292 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3293 cr->cr_prison = &prison0;
3294 prison_hold(cr->cr_prison);
3295#ifdef MAC
3296 mac_cred_associate_nfsd(cr);
3297#endif
3298 newusrp->lug_cred = cr;
3299 }
3300 free(grps, M_TEMP);
3301 }
3302 if (error) {
3303 free(newusrp, M_NFSUSERGROUP);
3304 goto out;
3305 }
3306 newusrp->lug_namelen = nidp->nid_namelen;
3307
3308 /*
3309 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3310 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3311 * The flags user_locked, username_locked, group_locked and
3312 * groupname_locked are set to indicate all of those hash lists are
3313 * locked. hp_name != NULL and hp_idnum != NULL indicates that
3314 * the respective one mutex is locked.
3315 */
3316 user_locked = username_locked = group_locked = groupname_locked = 0;
3317 hp_name = hp_idnum = NULL;
3318
3319 /*
3320 * Delete old entries, as required.
3321 */
3322 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3323 /* Must lock all username hash lists first, to avoid a LOR. */
3324 for (i = 0; i < nfsrv_lughashsize; i++)
3325 mtx_lock(&nfsusernamehash[i].mtx);
3326 username_locked = 1;
3327 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3328 mtx_lock(&hp_idnum->mtx);
3329 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3330 nusrp) {
3331 if (usrp->lug_uid == nidp->nid_uid)
3332 nfsrv_removeuser(usrp, 1);
3333 }
3334 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3335 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3336 newusrp->lug_namelen);
3337 mtx_lock(&hp_name->mtx);
3338 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3339 nusrp) {
3340 if (usrp->lug_namelen == newusrp->lug_namelen &&
3341 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3342 usrp->lug_namelen)) {
3343 thp = NFSUSERHASH(usrp->lug_uid);
3344 mtx_lock(&thp->mtx);
3345 nfsrv_removeuser(usrp, 1);
3346 mtx_unlock(&thp->mtx);
3347 }
3348 }
3349 hp_idnum = NFSUSERHASH(nidp->nid_uid);
3350 mtx_lock(&hp_idnum->mtx);
3351 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3352 /* Must lock all groupname hash lists first, to avoid a LOR. */
3353 for (i = 0; i < nfsrv_lughashsize; i++)
3354 mtx_lock(&nfsgroupnamehash[i].mtx);
3355 groupname_locked = 1;
3356 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3357 mtx_lock(&hp_idnum->mtx);
3358 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3359 nusrp) {
3360 if (usrp->lug_gid == nidp->nid_gid)
3361 nfsrv_removeuser(usrp, 0);
3362 }
3363 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3364 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3365 newusrp->lug_namelen);
3366 mtx_lock(&hp_name->mtx);
3367 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3368 nusrp) {
3369 if (usrp->lug_namelen == newusrp->lug_namelen &&
3370 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3371 usrp->lug_namelen)) {
3372 thp = NFSGROUPHASH(usrp->lug_gid);
3373 mtx_lock(&thp->mtx);
3374 nfsrv_removeuser(usrp, 0);
3375 mtx_unlock(&thp->mtx);
3376 }
3377 }
3378 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3379 mtx_lock(&hp_idnum->mtx);
3380 }
3381
3382 /*
3383 * Now, we can add the new one.
3384 */
3385 if (nidp->nid_usertimeout)
3386 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3387 else
3388 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3389 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3390 newusrp->lug_uid = nidp->nid_uid;
3391 thp = NFSUSERHASH(newusrp->lug_uid);
3392 mtx_assert(&thp->mtx, MA_OWNED);
3393 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3394 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3395 mtx_assert(&thp->mtx, MA_OWNED);
3396 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3397 atomic_add_int(&nfsrv_usercnt, 1);
3398 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3399 newusrp->lug_gid = nidp->nid_gid;
3400 thp = NFSGROUPHASH(newusrp->lug_gid);
3401 mtx_assert(&thp->mtx, MA_OWNED);
3402 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3403 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3404 mtx_assert(&thp->mtx, MA_OWNED);
3405 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3406 atomic_add_int(&nfsrv_usercnt, 1);
3407 } else {
3408 if (newusrp->lug_cred != NULL)
3409 crfree(newusrp->lug_cred);
3410 free(newusrp, M_NFSUSERGROUP);
3411 }
3412
3413 /*
3414 * Once per second, allow one thread to trim the cache.
3415 */
3416 if (lasttime < NFSD_MONOSEC &&
3417 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3418 /*
3419 * First, unlock the single mutexes, so that all entries
3420 * can be locked and any LOR is avoided.
3421 */
3422 if (hp_name != NULL) {
3423 mtx_unlock(&hp_name->mtx);
3424 hp_name = NULL;
3425 }
3426 if (hp_idnum != NULL) {
3427 mtx_unlock(&hp_idnum->mtx);
3428 hp_idnum = NULL;
3429 }
3430
3431 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3432 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3433 if (username_locked == 0) {
3434 for (i = 0; i < nfsrv_lughashsize; i++)
3435 mtx_lock(&nfsusernamehash[i].mtx);
3436 username_locked = 1;
3437 }
3438 KASSERT(user_locked == 0,
3439 ("nfssvc_idname: user_locked"));
3440 for (i = 0; i < nfsrv_lughashsize; i++)
3441 mtx_lock(&nfsuserhash[i].mtx);
3442 user_locked = 1;
3443 for (i = 0; i < nfsrv_lughashsize; i++) {
3444 TAILQ_FOREACH_SAFE(usrp,
3445 &nfsuserhash[i].lughead, lug_numhash,
3446 nusrp)
3447 if (usrp->lug_expiry < NFSD_MONOSEC)
3448 nfsrv_removeuser(usrp, 1);
3449 }
3450 for (i = 0; i < nfsrv_lughashsize; i++) {
3451 /*
3452 * Trim the cache using an approximate LRU
3453 * algorithm. This code deletes the least
3454 * recently used entry on each hash list.
3455 */
3456 if (nfsrv_usercnt <= nfsrv_usermax)
3457 break;
3458 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3459 if (usrp != NULL)
3460 nfsrv_removeuser(usrp, 1);
3461 }
3462 } else {
3463 if (groupname_locked == 0) {
3464 for (i = 0; i < nfsrv_lughashsize; i++)
3465 mtx_lock(&nfsgroupnamehash[i].mtx);
3466 groupname_locked = 1;
3467 }
3468 KASSERT(group_locked == 0,
3469 ("nfssvc_idname: group_locked"));
3470 for (i = 0; i < nfsrv_lughashsize; i++)
3471 mtx_lock(&nfsgrouphash[i].mtx);
3472 group_locked = 1;
3473 for (i = 0; i < nfsrv_lughashsize; i++) {
3474 TAILQ_FOREACH_SAFE(usrp,
3475 &nfsgrouphash[i].lughead, lug_numhash,
3476 nusrp)
3477 if (usrp->lug_expiry < NFSD_MONOSEC)
3478 nfsrv_removeuser(usrp, 0);
3479 }
3480 for (i = 0; i < nfsrv_lughashsize; i++) {
3481 /*
3482 * Trim the cache using an approximate LRU
3483 * algorithm. This code deletes the least
3484 * recently user entry on each hash list.
3485 */
3486 if (nfsrv_usercnt <= nfsrv_usermax)
3487 break;
3488 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3489 if (usrp != NULL)
3490 nfsrv_removeuser(usrp, 0);
3491 }
3492 }
3493 lasttime = NFSD_MONOSEC;
3494 atomic_store_rel_int(&onethread, 0);
3495 }
3496
3497 /* Now, unlock all locked mutexes. */
3498 if (hp_idnum != NULL)
3499 mtx_unlock(&hp_idnum->mtx);
3500 if (hp_name != NULL)
3501 mtx_unlock(&hp_name->mtx);
3502 if (user_locked != 0)
3503 for (i = 0; i < nfsrv_lughashsize; i++)
3504 mtx_unlock(&nfsuserhash[i].mtx);
3505 if (username_locked != 0)
3506 for (i = 0; i < nfsrv_lughashsize; i++)
3507 mtx_unlock(&nfsusernamehash[i].mtx);
3508 if (group_locked != 0)
3509 for (i = 0; i < nfsrv_lughashsize; i++)
3510 mtx_unlock(&nfsgrouphash[i].mtx);
3511 if (groupname_locked != 0)
3512 for (i = 0; i < nfsrv_lughashsize; i++)
3513 mtx_unlock(&nfsgroupnamehash[i].mtx);
3514out:
3515 NFSEXITCODE(error);
3516 return (error);
3517}
3518
3519/*
3520 * Remove a user/group name element.
3521 */
3522static void
3523nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
3524{
3525 struct nfsrv_lughash *hp;
3526
3527 if (isuser != 0) {
3528 hp = NFSUSERHASH(usrp->lug_uid);
3529 mtx_assert(&hp->mtx, MA_OWNED);
3530 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3531 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3532 mtx_assert(&hp->mtx, MA_OWNED);
3533 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3534 } else {
3535 hp = NFSGROUPHASH(usrp->lug_gid);
3536 mtx_assert(&hp->mtx, MA_OWNED);
3537 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3538 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
3539 mtx_assert(&hp->mtx, MA_OWNED);
3540 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
3541 }
3542 atomic_add_int(&nfsrv_usercnt, -1);
3543 if (usrp->lug_cred != NULL)
3544 crfree(usrp->lug_cred);
3545 free(usrp, M_NFSUSERGROUP);
3546}
3547
3548/*
3549 * This function scans a byte string and checks for UTF-8 compliance.
3550 * It returns 0 if it conforms and NFSERR_INVAL if not.
3551 */
3552APPLESTATIC int
3553nfsrv_checkutf8(u_int8_t *cp, int len)

--- 600 unchanged lines hidden ---