1/*
2   Unix SMB/CIFS implementation.
3   Manage connections_struct structures
4   Copyright (C) Andrew Tridgell 1998
5   Copyright (C) Alexander Bokovoy 2002
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#include "includes.h"
23
24/* Foxconn, add by MJ., 2010.03.29, for making a Semaphore. */
25#ifdef MAX_USB_ACCESS
26/* Obtain a binary semaphore��s ID, allocating if necessary. */
27int binary_semaphore_allocation (key_t key, int sem_flags)
28{
29    return semget (key, 1, sem_flags);
30}
31/* Deallocate a binary semaphore. All users must have finished their
32use. Returns -1 on failure. */
33int binary_semaphore_deallocate (int semid)
34{
35    union semun ignored_argument;
36    return semctl (semid, 1, IPC_RMID, ignored_argument);
37}
38
39/* Initialize a binary semaphore with a value of 1. */
40int binary_semaphore_initialize (int semid)
41{
42    union semun argument;
43    unsigned short values[1];
44    values[0] = 1;
45    argument.array = values;
46    return semctl (semid, 0, SETALL, argument);
47}
48/* Wait on a binary semaphore. Block until the semaphore value is positive, then
49decrement it by 1. */
50int binary_semaphore_wait (int semid)
51{
52    struct sembuf operations[1];
53    /* Use the first (and only) semaphore. */
54    operations[0].sem_num = 0;
55    /* Decrement by 1. */
56    operations[0].sem_op = -1;
57    /* Permit undo��ing. */
58    operations[0].sem_flg = SEM_UNDO;
59    return semop (semid, operations, 1);
60}
61
62/* Post to a binary semaphore: increment its value by 1.
63This returns immediately. */
64int binary_semaphore_post (int semid)
65{
66    struct sembuf operations[1];
67    /* Use the first (and only) semaphore. */
68    operations[0].sem_num = 0;
69    /* Increment by 1. */
70    operations[0].sem_op = 1;
71    /* Permit undo��ing. */
72    operations[0].sem_flg = SEM_UNDO;
73    return semop (semid, operations, 1);
74}
75#endif //End of MAX_USB_ACCESS
76/* Foxconn, ened by MJ., 2010.03.29 */
77
78
79/* The connections bitmap is expanded in increments of BITMAP_BLOCK_SZ. The
80 * maximum size of the bitmap is the largest positive integer, but you will hit
81 * the "max connections" limit, looong before that.
82 */
83#define BITMAP_BLOCK_SZ 128
84
85static connection_struct *Connections;
86
87/* number of open connections */
88static struct bitmap *bmap;
89static int num_open;
90
91/****************************************************************************
92init the conn structures
93****************************************************************************/
94void conn_init(void)
95{
96	bmap = bitmap_allocate(BITMAP_BLOCK_SZ);
97}
98
99/****************************************************************************
100return the number of open connections
101****************************************************************************/
102int conn_num_open(void)
103{
104	return num_open;
105}
106
107
108/****************************************************************************
109check if a snum is in use
110****************************************************************************/
111BOOL conn_snum_used(int snum)
112{
113	connection_struct *conn;
114	for (conn=Connections;conn;conn=conn->next) {
115		if (conn->service == snum) {
116			return(True);
117		}
118	}
119	return(False);
120}
121
122
123/****************************************************************************
124find a conn given a cnum
125****************************************************************************/
126connection_struct *conn_find(unsigned cnum)
127{
128	int count=0;
129	connection_struct *conn;
130
131	for (conn=Connections;conn;conn=conn->next,count++) {
132		if (conn->cnum == cnum) {
133			if (count > 10) {
134				DLIST_PROMOTE(Connections, conn);
135			}
136			return conn;
137		}
138	}
139
140	return NULL;
141}
142
143
144/****************************************************************************
145  find first available connection slot, starting from a random position.
146The randomisation stops problems with the server dieing and clients
147thinking the server is still available.
148****************************************************************************/
149connection_struct *conn_new(void)
150{
151	TALLOC_CTX *mem_ctx;
152	connection_struct *conn;
153	int i;
154    int find_offset = 1;
155    /* Foxconn, added by MJ., 2010.03.26 */
156#if 0
157    extern CON_STATISTIC *con_st;
158
159    if(con_st != NULL){
160        dbgtext("->total con num: %d, %s\n", con_st->num, __FUNCTION__);
161        binary_semaphore_wait (con_st->sem_id);
162        if(con_st->num >= MAX_CON_NUM){
163            binary_semaphore_post (con_st->sem_id);
164            return NULL;
165        }
166        binary_semaphore_post (con_st->sem_id);
167    }
168#endif
169    /* Foxconn, ended by MJ., 2010.03.26*/
170
171find_again:
172	i = bitmap_find(bmap, find_offset);
173
174	if (i == -1) {
175                /* Expand the connections bitmap. */
176                int             oldsz = bmap->n;
177                int             newsz = bmap->n + BITMAP_BLOCK_SZ;
178                struct bitmap * nbmap;
179
180                if (newsz <= 0) {
181                        /* Integer wrap. */
182		        DEBUG(0,("ERROR! Out of connection structures\n"));
183                        return NULL;
184                }
185
186		DEBUG(4,("resizing connections bitmap from %d to %d\n",
187                        oldsz, newsz));
188
189                nbmap = bitmap_allocate(newsz);
190
191                bitmap_copy(nbmap, bmap);
192                bitmap_free(bmap);
193
194                bmap = nbmap;
195                find_offset = oldsz; /* Start next search in the new portion. */
196
197                goto find_again;
198	}
199
200	if ((mem_ctx=talloc_init("connection_struct"))==NULL) {
201		DEBUG(0,("talloc_init(connection_struct) failed!\n"));
202
203		return NULL;
204	}
205
206	if ((conn=TALLOC_ZERO_P(mem_ctx, connection_struct))==NULL) {
207		DEBUG(0,("talloc_zero() failed!\n"));
208
209		return NULL;
210	}
211	conn->mem_ctx = mem_ctx;
212	conn->cnum = i;
213
214	bitmap_set(bmap, i);
215
216	num_open++;
217
218	string_set(&conn->user,"");
219	string_set(&conn->dirpath,"");
220	string_set(&conn->connectpath,"");
221	string_set(&conn->origpath,"");
222
223	DLIST_ADD(Connections, conn);
224
225	return conn;
226}
227
228/****************************************************************************
229close all conn structures
230****************************************************************************/
231void conn_close_all(void)
232{
233	connection_struct *conn, *next;
234	for (conn=Connections;conn;conn=next) {
235		next=conn->next;
236		set_current_service(conn, 0, True);
237		close_cnum(conn, conn->vuid);
238	}
239}
240
241/****************************************************************************
242 Idle inactive connections.
243****************************************************************************/
244
245BOOL conn_idle_all(time_t t, int deadtime)
246{
247	pipes_struct *plist = NULL;
248	BOOL allidle = True;
249	connection_struct *conn, *next;
250
251	for (conn=Connections;conn;conn=next) {
252		next=conn->next;
253		/* close dirptrs on connections that are idle */
254		if ((t-conn->lastused) > DPTR_IDLE_TIMEOUT)
255			dptr_idlecnum(conn);
256
257		if (conn->num_files_open > 0 ||
258		    (t-conn->lastused)<deadtime)
259			allidle = False;
260	}
261
262	/*
263	 * Check all pipes for any open handles. We cannot
264	 * idle with a handle open.
265	 */
266
267	for (plist = get_first_internal_pipe(); plist; plist = get_next_internal_pipe(plist))
268		if (plist->pipe_handles && plist->pipe_handles->count)
269			allidle = False;
270
271	return allidle;
272}
273
274/****************************************************************************
275 Clear a vuid out of the validity cache, and as the 'owner' of a connection.
276****************************************************************************/
277
278void conn_clear_vuid_cache(uint16 vuid)
279{
280	connection_struct *conn;
281	unsigned int i;
282
283	for (conn=Connections;conn;conn=conn->next) {
284		if (conn->vuid == vuid) {
285			conn->vuid = UID_FIELD_INVALID;
286		}
287
288		for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) {
289			if (conn->vuid_cache.array[i].vuid == vuid) {
290				struct vuid_cache_entry *ent = &conn->vuid_cache.array[i];
291				ent->vuid = UID_FIELD_INVALID;
292				ent->read_only = False;
293				ent->admin_user = False;
294			}
295		}
296	}
297}
298
299/****************************************************************************
300 Free a conn structure.
301****************************************************************************/
302
303void conn_free(connection_struct *conn)
304{
305 	vfs_handle_struct *handle = NULL, *thandle = NULL;
306 	TALLOC_CTX *mem_ctx = NULL;
307
308	/* Free vfs_connection_struct */
309	handle = conn->vfs_handles;
310	while(handle) {
311		DLIST_REMOVE(conn->vfs_handles, handle);
312		thandle = handle->next;
313		if (handle->free_data)
314			handle->free_data(&handle->data);
315		handle = thandle;
316	}
317
318	DLIST_REMOVE(Connections, conn);
319
320	if (conn->ngroups && conn->groups) {
321		SAFE_FREE(conn->groups);
322		conn->ngroups = 0;
323	}
324
325	if (conn->nt_user_token) {
326		delete_nt_token(&(conn->nt_user_token));
327	}
328
329	free_namearray(conn->veto_list);
330	free_namearray(conn->hide_list);
331	free_namearray(conn->veto_oplock_list);
332
333	string_free(&conn->user);
334	string_free(&conn->dirpath);
335	string_free(&conn->connectpath);
336	string_free(&conn->origpath);
337
338	bitmap_clear(bmap, conn->cnum);
339	num_open--;
340
341	mem_ctx = conn->mem_ctx;
342	ZERO_STRUCTP(conn);
343	talloc_destroy(mem_ctx);
344}
345
346
347/****************************************************************************
348receive a smbcontrol message to forcibly unmount a share
349the message contains just a share name and all instances of that
350share are unmounted
351the special sharename '*' forces unmount of all shares
352****************************************************************************/
353void msg_force_tdis(int msg_type, pid_t pid, void *buf, size_t len)
354{
355	connection_struct *conn, *next;
356	fstring sharename;
357
358	fstrcpy(sharename, buf);
359
360	if (strcmp(sharename, "*") == 0) {
361		DEBUG(1,("Forcing close of all shares\n"));
362		conn_close_all();
363		return;
364	}
365
366	for (conn=Connections;conn;conn=next) {
367		next=conn->next;
368		if (strequal(lp_servicename(conn->service), sharename)) {
369			DEBUG(1,("Forcing close of share %s cnum=%d\n",
370				 sharename, conn->cnum));
371			close_cnum(conn, (uint16)-1);
372		}
373	}
374}
375