r22418: Support running under launchd. We abstract the method of obtaining
[ira/wip.git] / source3 / smbd / connection.c
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
23 static TDB_CONTEXT *tdb;
24
25 /****************************************************************************
26  Return the connection tdb context (used for message send all).
27 ****************************************************************************/
28
29 TDB_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
38 static 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 = (uint8 *)pkey;
54         pkbuf->dsize = sizeof(*pkey);
55 }
56
57 /****************************************************************************
58  Delete a connection record.
59 ****************************************************************************/
60
61 BOOL 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
83 struct 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
94 static 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
103         memcpy(&crec, dbuf.dptr, sizeof(crec));
104  
105         if (crec.cnum == -1) {
106                 return 0;
107         }
108
109         /* If the pid was not found delete the entry from connections.tdb */
110
111         if (cs->Clear && !process_exists(crec.pid) && (errno == ESRCH)) {
112                 DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n",
113                         procid_str_static(&crec.pid), crec.cnum, crec.servicename));
114                 if (tdb_delete(the_tdb, kbuf) != 0)
115                         DEBUG(0,("count_fn: tdb_delete failed with error %s\n", tdb_errorstr(tdb) ));
116                 return 0;
117         }
118  
119         if (cs->name) {
120                 /* We are counting all the connections to a given share. */
121                 if (strequal(crec.servicename, cs->name)) {
122                         cs->curr_connections++;
123                 }
124         } else {
125                 /* We are counting all the connections. Static registrations
126                  * like the lpq backgroud process and the smbd daemon process
127                  * have a cnum of -1, so won't be counted here.
128                  */
129                 cs->curr_connections++;
130         }
131
132         return 0;
133 }
134
135 /****************************************************************************
136  Claim an entry in the connections database.
137 ****************************************************************************/
138
139 int count_current_connections( const char *sharename, BOOL clear  )
140 {
141         struct count_stat cs;
142
143         cs.mypid = sys_getpid();
144         cs.curr_connections = 0;
145         cs.name = sharename;
146         cs.Clear = clear;
147
148         /*
149          * This has a race condition, but locking the chain before hand is worse
150          * as it leads to deadlock.
151          */
152
153         if (tdb_traverse(tdb, count_fn, &cs) == -1) {
154                 DEBUG(0,("count_current_connections: traverse of connections.tdb failed with error %s\n",
155                         tdb_errorstr(tdb) ));
156                 DEBUGADD(0, ("count_current_connections: connection count of %d might not be accurate",
157                             cs.curr_connections));
158         }
159
160         /* If the traverse failed part-way through, we at least return
161          * as many connections as we had already counted. If it failed
162          * right at the start, we will return 0, which is about all we
163          * can do anywway.
164          */
165
166         return cs.curr_connections;
167 }
168
169 /****************************************************************************
170  Count the number of connections open across all shares.
171 ****************************************************************************/
172
173 int count_all_current_connections(void)
174 {
175         return count_current_connections(NULL, True /* clear stale entries */);
176 }
177
178 /****************************************************************************
179  Claim an entry in the connections database.
180 ****************************************************************************/
181
182 BOOL claim_connection(connection_struct *conn, const char *name,int max_connections,BOOL Clear, uint32 msg_flags)
183 {
184         struct connections_key key;
185         struct connections_data crec;
186         TDB_DATA kbuf, dbuf;
187
188         if (!tdb) {
189                 if ( (tdb =conn_tdb_ctx()) == NULL ) {
190                         return False;
191                 }
192         }
193         
194         /*
195          * Enforce the max connections parameter.
196          */
197
198         if (max_connections > 0) {
199                 int curr_connections;
200                 
201                 curr_connections = count_current_connections( lp_servicename(SNUM(conn)), True );
202
203                 if (curr_connections >= max_connections) {
204                         DEBUG(1,("claim_connection: Max connections (%d) exceeded for %s\n",
205                                 max_connections, name ));
206                         return False;
207                 }
208         }
209
210         DEBUG(5,("claiming %s %d\n",name,max_connections));
211
212         make_conn_key(conn, name, &kbuf, &key);
213
214         /* fill in the crec */
215         ZERO_STRUCT(crec);
216         crec.magic = 0x280267;
217         crec.pid = procid_self();
218         crec.cnum = conn?conn->cnum:-1;
219         if (conn) {
220                 crec.uid = conn->uid;
221                 crec.gid = conn->gid;
222                 safe_strcpy(crec.servicename,
223                             lp_servicename(SNUM(conn)),sizeof(crec.servicename)-1);
224         }
225         crec.start = time(NULL);
226         crec.bcast_msg_flags = msg_flags;
227         
228         safe_strcpy(crec.machine,get_remote_machine_name(),sizeof(crec.machine)-1);
229         safe_strcpy(crec.addr,conn?conn->client_address:client_addr(),sizeof(crec.addr)-1);
230
231         dbuf.dptr = (uint8 *)&crec;
232         dbuf.dsize = sizeof(crec);
233
234         if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
235                 DEBUG(0,("claim_connection: tdb_store failed with error %s.\n",
236                         tdb_errorstr(tdb) ));
237                 return False;
238         }
239
240         return True;
241 }
242
243 BOOL register_message_flags(BOOL doreg, uint32 msg_flags)
244 {
245         struct connections_key key;
246         struct connections_data *pcrec;
247         TDB_DATA kbuf, dbuf;
248
249         if (!tdb)
250                 return False;
251
252         DEBUG(10,("register_message_flags: %s flags 0x%x\n",
253                 doreg ? "adding" : "removing",
254                 (unsigned int)msg_flags ));
255
256         make_conn_key(NULL, "", &kbuf, &key);
257
258         dbuf = tdb_fetch(tdb, kbuf);
259         if (!dbuf.dptr) {
260                 DEBUG(0,("register_message_flags: tdb_fetch failed: %s\n",
261                         tdb_errorstr(tdb)));
262                 return False;
263         }
264
265         pcrec = (struct connections_data *)dbuf.dptr;
266         if (doreg)
267                 pcrec->bcast_msg_flags |= msg_flags;
268         else
269                 pcrec->bcast_msg_flags &= ~msg_flags;
270
271         if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
272                 DEBUG(0,("register_message_flags: tdb_store failed: %s.\n",
273                         tdb_errorstr(tdb) ));
274                 SAFE_FREE(dbuf.dptr);
275                 return False;
276         }
277
278         DEBUG(10,("register_message_flags: new flags 0x%x\n",
279                 (unsigned int)pcrec->bcast_msg_flags ));
280
281         SAFE_FREE(dbuf.dptr);
282         return True;
283 }
284
285 /*********************************************************************
286 *********************************************************************/
287
288 static TDB_DATA* make_pipe_rec_key( struct pipe_open_rec *prec )
289 {
290         TDB_DATA *kbuf = NULL;
291         fstring key_string;
292         
293         if ( !prec )
294                 return NULL;
295         
296         if ( (kbuf = TALLOC_P(prec, TDB_DATA)) == NULL ) {
297                 return NULL;
298         }
299         
300         snprintf( key_string, sizeof(key_string), "%s/%d/%d",
301                 prec->name, procid_to_pid(&prec->pid), prec->pnum );
302                 
303         *kbuf = string_term_tdb_data(talloc_strdup(prec, key_string));
304         if (kbuf->dptr == NULL )
305                 return NULL;
306
307         return kbuf;
308 }
309
310 /*********************************************************************
311 *********************************************************************/
312
313 static void fill_pipe_open_rec( struct pipe_open_rec *prec, smb_np_struct *p )
314 {
315         prec->pid = pid_to_procid(sys_getpid());
316         prec->pnum = p->pnum;
317         prec->uid = geteuid();
318         fstrcpy( prec->name, p->name );
319
320         return;
321 }
322
323 /*********************************************************************
324 *********************************************************************/
325
326 BOOL store_pipe_opendb( smb_np_struct *p )
327 {
328         struct pipe_open_rec *prec;
329         TDB_DATA *key;
330         TDB_DATA data;
331         TDB_CONTEXT *pipe_tdb;
332         BOOL ret = False;
333         
334         if ( (prec = TALLOC_P( NULL, struct pipe_open_rec)) == NULL ) {
335                 DEBUG(0,("store_pipe_opendb: talloc failed!\n"));
336                 return False;
337         }
338         
339         fill_pipe_open_rec( prec, p );
340         if ( (key = make_pipe_rec_key( prec )) == NULL ) {
341                 goto done;
342         }
343         
344         data.dptr = (uint8 *)prec;
345         data.dsize = sizeof(struct pipe_open_rec);
346         
347         if ( (pipe_tdb = conn_tdb_ctx() ) == NULL ) {
348                 goto done;
349         }
350         
351         ret = (tdb_store( pipe_tdb, *key, data, TDB_REPLACE ) != -1);
352         
353 done:
354         TALLOC_FREE( prec );    
355         return ret;
356 }
357
358 /*********************************************************************
359 *********************************************************************/
360
361 BOOL delete_pipe_opendb( smb_np_struct *p )
362 {
363         struct pipe_open_rec *prec;
364         TDB_DATA *key;
365         TDB_CONTEXT *pipe_tdb;
366         BOOL ret = False;
367         
368         if ( (prec = TALLOC_P( NULL, struct pipe_open_rec)) == NULL ) {
369                 DEBUG(0,("store_pipe_opendb: talloc failed!\n"));
370                 return False;
371         }
372         
373         fill_pipe_open_rec( prec, p );
374         if ( (key = make_pipe_rec_key( prec )) == NULL ) {
375                 goto done;
376         }
377         
378         if ( (pipe_tdb = conn_tdb_ctx() ) == NULL ) {
379                 goto done;
380         }
381
382         ret = (tdb_delete( pipe_tdb, *key ) != -1 );
383         
384 done:
385         TALLOC_FREE( prec );
386         return ret;
387 }