4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
33 #include <sys/types.h>
36 #include <sys/param.h>
39 #include <netconfig.h>
43 #include <sys/errno.h>
44 #include <sys/resource.h>
45 #include <rpcsvc/mount.h>
46 #include <sys/pathconf.h>
47 #include <sys/systeminfo.h>
48 #include <sys/utsname.h>
53 #include <sharefs/share.h>
54 #include "../lib/sharetab.h"
63 struct cache_entry
*cache_next
;
66 static struct cache_entry
*cache_head
;
68 #define VALID_TIME 60 /* seconds */
70 static rwlock_t cache_lock
; /* protect the cache chain */
72 static void cache_free(struct cache_entry
*entry
);
73 static int cache_check(char *host
, char **grl
, int grc
, int *belong
);
74 static void cache_enter(char *host
, char **grl
, int grc
, int belong
);
80 (void) rwlock_init(&cache_lock
, USYNC_THREAD
, NULL
);
84 * Check whether any of the hostnames in clnames are
85 * members (or non-members) of the netgroups in glist.
86 * Since the innetgr lookup is rather expensive, the
87 * result is cached. The cached entry is valid only
88 * for VALID_TIME seconds. This works well because
89 * typically these lookups occur in clusters when
90 * a client is mounting.
92 * Note that this routine establishes a host membership
93 * in a list of netgroups - we've no idea just which
94 * netgroup in the list it is a member of.
96 * glist is a character array containing grc strings
97 * representing netgroup names (optionally prefixed
98 * with '-'). Each string is ended with '\0' and
99 * followed immediately by the next string.
102 netgroup_check(struct nd_hostservlist
*clnames
, char *glist
, int grc
)
106 int nhosts
= clnames
->h_cnt
;
113 if (domain
== NULL
) {
116 domain
= exmalloc(SYS_NMLN
);
117 ssize
= sysinfo(SI_SRPC_DOMAIN
, domain
, SYS_NMLN
);
118 if (ssize
> SYS_NMLN
) {
120 domain
= exmalloc(ssize
);
121 ssize
= sysinfo(SI_SRPC_DOMAIN
, domain
, ssize
);
123 /* Check for error in syscall or NULL domain name */
125 syslog(LOG_ERR
, "No default domain set");
130 grl
= calloc(grc
, sizeof (char *));
134 for (i
= 0, gr
= glist
; i
< grc
&& !belong
; ) {
136 * If the netgroup name has a '-' prepended
137 * then a match of this name implies a failure
138 * instead of success.
140 response
= (*gr
!= '-') ? 1 : 0;
143 * Subsequent names with or without a '-' (but no mix)
144 * can be grouped together for a single check.
146 for (n
= 0; i
< grc
; i
++, n
++, gr
+= strlen(gr
) + 1) {
147 if ((response
&& *gr
== '-') ||
148 (!response
&& *gr
!= '-'))
151 grl
[n
] = response
? gr
: gr
+ 1;
154 host0
= clnames
->h_hostservs
[0].h_host
;
157 * If not in cache check the netgroup for each
158 * of the hosts names (usually just one).
159 * Enter the result into the cache.
161 if (!cache_check(host0
, grl
, n
, &belong
)) {
162 for (j
= 0; j
< nhosts
&& !belong
; j
++) {
163 host
= clnames
->h_hostservs
[j
].h_host
;
165 if (__multi_innetgr(n
, grl
,
172 cache_enter(host0
, grl
, n
, belong
);
177 return (belong
? response
: 0);
181 * Free a cache entry and all entries
182 * further down the chain since they
183 * will also be expired.
186 cache_free(struct cache_entry
*entry
)
188 struct cache_entry
*ce
, *next
;
191 for (ce
= entry
; ce
; ce
= next
) {
193 free(ce
->cache_host
);
194 for (i
= 0; i
< ce
->cache_grc
; i
++)
195 if (ce
->cache_grl
[i
])
196 free(ce
->cache_grl
[i
]);
199 next
= ce
->cache_next
;
205 * Search the entries in the cache chain looking
206 * for an entry with a matching hostname and group
207 * list. If a match is found then return the "belong"
208 * value which may be 1 or 0 depending on whether the
209 * client is a member of the list or not. This is
210 * both a positive and negative cache.
212 * Cache entries have a validity of VALID_TIME seconds.
213 * If we find an expired entry then blow away the entry
214 * and the rest of the chain since entries further down
215 * the chain will be expired too because we always add
216 * new entries to the head of the chain.
219 cache_check(char *host
, char **grl
, int grc
, int *belong
)
221 struct cache_entry
*ce
, *prev
;
222 time_t timenow
= time(NULL
);
225 (void) rw_rdlock(&cache_lock
);
227 for (ce
= cache_head
; ce
; ce
= ce
->cache_next
) {
230 * If we find a stale entry, there can't
231 * be any valid entries from here on.
232 * Acquire a write lock, search the chain again
233 * and delete the stale entry and all following
236 if (timenow
> ce
->cache_time
) {
237 (void) rw_unlock(&cache_lock
);
238 (void) rw_wrlock(&cache_lock
);
240 for (prev
= NULL
, ce
= cache_head
; ce
;
241 prev
= ce
, ce
= ce
->cache_next
)
242 if (timenow
> ce
->cache_time
)
247 prev
->cache_next
= NULL
;
253 (void) rw_unlock(&cache_lock
);
257 if (ce
->cache_grc
!= grc
)
258 continue; /* no match */
260 if (strcasecmp(host
, ce
->cache_host
) != 0)
261 continue; /* no match */
263 for (i
= 0; i
< grc
; i
++)
264 if (strcasecmp(ce
->cache_grl
[i
], grl
[i
]) != 0)
265 break; /* no match */
269 *belong
= ce
->cache_belong
;
270 (void) rw_unlock(&cache_lock
);
275 (void) rw_unlock(&cache_lock
);
281 * Put a new entry in the cache chain by
282 * prepending it to the front.
283 * If there isn't enough memory then just give up.
286 cache_enter(char *host
, char **grl
, int grc
, int belong
)
288 struct cache_entry
*entry
;
291 entry
= malloc(sizeof (*entry
));
295 (void) memset((caddr_t
)entry
, 0, sizeof (*entry
));
296 entry
->cache_host
= strdup(host
);
297 if (entry
->cache_host
== NULL
) {
302 entry
->cache_time
= time(NULL
) + VALID_TIME
;
303 entry
->cache_belong
= belong
;
304 entry
->cache_grl
= malloc(grc
* sizeof (char *));
305 if (entry
->cache_grl
== NULL
) {
310 for (i
= 0; i
< grc
; i
++) {
311 entry
->cache_grl
[i
] = strdup(grl
[i
]);
312 if (entry
->cache_grl
[i
] == NULL
) {
313 entry
->cache_grc
= i
;
319 entry
->cache_grc
= grc
;
321 (void) rw_wrlock(&cache_lock
);
322 entry
->cache_next
= cache_head
;
324 (void) rw_unlock(&cache_lock
);
331 netgrp_cache_flush(void)
333 (void) rw_wrlock(&cache_lock
);
334 cache_free(cache_head
);
336 (void) rw_unlock(&cache_lock
);