source: trunk/samba/source/smbd/connection.c @ 30

Last change on this file since 30 was 30, checked in by Paul Smedley, 14 years ago

Code updated to Samba 3.0.25rc2 level

File size: 9.4 KB
Line 
1/*
2   Unix SMB/CIFS implementation.
3   connection claim routines
4   Copyright (C) Andrew Tridgell 1998
5   
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10   
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15   
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include "includes.h"
22
23static TDB_CONTEXT *tdb;
24
25/****************************************************************************
26 Return the connection tdb context (used for message send all).
27****************************************************************************/
28
29TDB_CONTEXT *conn_tdb_ctx(void)
30{
31        if (!tdb)
32                tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, 
33                               O_RDWR | O_CREAT, 0644);
34
35        return tdb;
36}
37
38static void make_conn_key(connection_struct *conn, const char *name, TDB_DATA *pkbuf, struct connections_key *pkey)
39{
40        ZERO_STRUCTP(pkey);
41        pkey->pid = procid_self();
42        pkey->cnum = conn?conn->cnum:-1;
43        fstrcpy(pkey->name, name);
44#ifdef DEVELOPER
45        /* valgrind fixer... */
46        {
47                size_t sl = strlen(pkey->name);
48                if (sizeof(fstring)-sl)
49                        memset(&pkey->name[sl], '\0', sizeof(fstring)-sl);
50        }
51#endif
52
53        pkbuf->dptr = (char *)pkey;
54        pkbuf->dsize = sizeof(*pkey);
55}
56
57/****************************************************************************
58 Delete a connection record.
59****************************************************************************/
60
61BOOL yield_connection(connection_struct *conn, const char *name)
62{
63        struct connections_key key;
64        TDB_DATA kbuf;
65
66        if (!tdb)
67                return False;
68
69        DEBUG(3,("Yielding connection to %s\n",name));
70
71        make_conn_key(conn, name, &kbuf, &key);
72
73        if (tdb_delete(tdb, kbuf) != 0) {
74                int dbg_lvl = (!conn && (tdb_error(tdb) == TDB_ERR_NOEXIST)) ? 3 : 0;
75                DEBUG(dbg_lvl,("yield_connection: tdb_delete for name %s failed with error %s.\n",
76                        name, tdb_errorstr(tdb) ));
77                return (False);
78        }
79
80        return(True);
81}
82
83struct count_stat {
84        pid_t mypid;
85        int curr_connections;
86        const char *name;
87        BOOL Clear;
88};
89
90/****************************************************************************
91 Count the entries belonging to a service in the connection db.
92****************************************************************************/
93
94static int count_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *udp)
95{
96        struct connections_data crec;
97        struct count_stat *cs = (struct count_stat *)udp;
98 
99        if (dbuf.dsize != sizeof(crec))
100                return 0;
101
102        memcpy(&crec, dbuf.dptr, sizeof(crec));
103 
104        if (crec.cnum == -1)
105                return 0;
106
107        /* If the pid was not found delete the entry from connections.tdb */
108
109        if (cs->Clear && !process_exists(crec.pid) && (errno == ESRCH)) {
110                DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n",
111                        procid_str_static(&crec.pid), crec.cnum, crec.servicename));
112                if (tdb_delete(the_tdb, kbuf) != 0)
113                        DEBUG(0,("count_fn: tdb_delete failed with error %s\n", tdb_errorstr(tdb) ));
114                return 0;
115        }
116
117        if (strequal(crec.servicename, cs->name))
118                cs->curr_connections++;
119
120        return 0;
121}
122
123/****************************************************************************
124 Claim an entry in the connections database.
125****************************************************************************/
126
127int count_current_connections( const char *sharename, BOOL clear  )
128{
129        struct count_stat cs;
130
131        cs.mypid = sys_getpid();
132        cs.curr_connections = 0;
133        cs.name = sharename;
134        cs.Clear = clear;
135
136        /*
137         * This has a race condition, but locking the chain before hand is worse
138         * as it leads to deadlock.
139         */
140
141        if (tdb_traverse(tdb, count_fn, &cs) == -1) {
142                DEBUG(0,("claim_connection: traverse of connections.tdb failed with error %s.\n",
143                        tdb_errorstr(tdb) ));
144                return False;
145        }
146       
147        return cs.curr_connections;
148}
149
150/****************************************************************************
151 Claim an entry in the connections database.
152****************************************************************************/
153
154BOOL claim_connection(connection_struct *conn, const char *name,int max_connections,BOOL Clear, uint32 msg_flags)
155{
156        struct connections_key key;
157        struct connections_data crec;
158        TDB_DATA kbuf, dbuf;
159
160        if (!tdb) {
161                if ( (tdb =conn_tdb_ctx()) == NULL ) {
162                        return False;
163                }
164        }
165       
166        /*
167         * Enforce the max connections parameter.
168         */
169
170        if (max_connections > 0) {
171                int curr_connections;
172               
173                curr_connections = count_current_connections( lp_servicename(SNUM(conn)), True );
174
175                if (curr_connections >= max_connections) {
176                        DEBUG(1,("claim_connection: Max connections (%d) exceeded for %s\n",
177                                max_connections, name ));
178                        return False;
179                }
180        }
181
182        DEBUG(5,("claiming %s %d\n",name,max_connections));
183
184        make_conn_key(conn, name, &kbuf, &key);
185
186        /* fill in the crec */
187        ZERO_STRUCT(crec);
188        crec.magic = 0x280267;
189        crec.pid = procid_self();
190        crec.cnum = conn?conn->cnum:-1;
191        if (conn) {
192                crec.uid = conn->uid;
193                crec.gid = conn->gid;
194                safe_strcpy(crec.servicename,
195                            lp_servicename(SNUM(conn)),sizeof(crec.servicename)-1);
196        }
197        crec.start = time(NULL);
198        crec.bcast_msg_flags = msg_flags;
199       
200        safe_strcpy(crec.machine,get_remote_machine_name(),sizeof(crec.machine)-1);
201        safe_strcpy(crec.addr,conn?conn->client_address:client_addr(),sizeof(crec.addr)-1);
202
203        dbuf.dptr = (char *)&crec;
204        dbuf.dsize = sizeof(crec);
205
206        if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
207                DEBUG(0,("claim_connection: tdb_store failed with error %s.\n",
208                        tdb_errorstr(tdb) ));
209                return False;
210        }
211
212        return True;
213}
214
215BOOL register_message_flags(BOOL doreg, uint32 msg_flags)
216{
217        struct connections_key key;
218        struct connections_data *pcrec;
219        TDB_DATA kbuf, dbuf;
220
221        if (!tdb)
222                return False;
223
224        DEBUG(10,("register_message_flags: %s flags 0x%x\n",
225                doreg ? "adding" : "removing",
226                (unsigned int)msg_flags ));
227
228        make_conn_key(NULL, "", &kbuf, &key);
229
230        dbuf = tdb_fetch(tdb, kbuf);
231        if (!dbuf.dptr) {
232                DEBUG(0,("register_message_flags: tdb_fetch failed: %s\n",
233                        tdb_errorstr(tdb)));
234                return False;
235        }
236
237        pcrec = (struct connections_data *)dbuf.dptr;
238        if (doreg)
239                pcrec->bcast_msg_flags |= msg_flags;
240        else
241                pcrec->bcast_msg_flags &= ~msg_flags;
242
243        if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
244                DEBUG(0,("register_message_flags: tdb_store failed: %s.\n",
245                        tdb_errorstr(tdb) ));
246                SAFE_FREE(dbuf.dptr);
247                return False;
248        }
249
250        DEBUG(10,("register_message_flags: new flags 0x%x\n",
251                (unsigned int)pcrec->bcast_msg_flags ));
252
253        SAFE_FREE(dbuf.dptr);
254        return True;
255}
256
257/*********************************************************************
258*********************************************************************/
259
260static TDB_DATA* make_pipe_rec_key( struct pipe_open_rec *prec )
261{
262        TDB_DATA *kbuf = NULL;
263        fstring key_string;
264       
265        if ( !prec )
266                return NULL;
267       
268        if ( (kbuf = TALLOC_P(prec, TDB_DATA)) == NULL ) {
269                return NULL;
270        }
271       
272        snprintf( key_string, sizeof(key_string), "%s/%d/%d",
273                prec->name, procid_to_pid(&prec->pid), prec->pnum );
274               
275        if ( (kbuf->dptr = talloc_strdup(prec, key_string)) == NULL )
276                return NULL;
277               
278        kbuf->dsize = strlen(key_string)+1;
279       
280        return kbuf;
281}
282
283/*********************************************************************
284*********************************************************************/
285
286static void fill_pipe_open_rec( struct pipe_open_rec *prec, smb_np_struct *p )
287{
288        prec->pid = pid_to_procid(sys_getpid());
289        prec->pnum = p->pnum;
290        prec->uid = geteuid();
291        fstrcpy( prec->name, p->name );
292
293        return;
294}
295
296/*********************************************************************
297*********************************************************************/
298
299BOOL store_pipe_opendb( smb_np_struct *p )
300{
301        struct pipe_open_rec *prec;
302        TDB_DATA *key;
303        TDB_DATA data;
304        TDB_CONTEXT *pipe_tdb;
305        BOOL ret = False;
306       
307        if ( (prec = TALLOC_P( NULL, struct pipe_open_rec)) == NULL ) {
308                DEBUG(0,("store_pipe_opendb: talloc failed!\n"));
309                return False;
310        }
311       
312        fill_pipe_open_rec( prec, p );
313        if ( (key = make_pipe_rec_key( prec )) == NULL ) {
314                goto done;
315        }
316       
317        data.dptr = (char*)prec;
318        data.dsize = sizeof(struct pipe_open_rec);
319       
320        if ( (pipe_tdb = conn_tdb_ctx() ) == NULL ) {
321                goto done;
322        }
323       
324        ret = (tdb_store( pipe_tdb, *key, data, TDB_REPLACE ) != -1);
325       
326done:
327        TALLOC_FREE( prec );   
328        return ret;
329}
330
331/*********************************************************************
332*********************************************************************/
333
334BOOL delete_pipe_opendb( smb_np_struct *p )
335{
336        struct pipe_open_rec *prec;
337        TDB_DATA *key;
338        TDB_CONTEXT *pipe_tdb;
339        BOOL ret = False;
340       
341        if ( (prec = TALLOC_P( NULL, struct pipe_open_rec)) == NULL ) {
342                DEBUG(0,("store_pipe_opendb: talloc failed!\n"));
343                return False;
344        }
345       
346        fill_pipe_open_rec( prec, p );
347        if ( (key = make_pipe_rec_key( prec )) == NULL ) {
348                goto done;
349        }
350       
351        if ( (pipe_tdb = conn_tdb_ctx() ) == NULL ) {
352                goto done;
353        }
354
355        ret = (tdb_delete( pipe_tdb, *key ) != -1 );
356       
357done:
358        TALLOC_FREE( prec );
359        return ret;
360}
Note: See TracBrowser for help on using the repository browser.