utmp compile fix from peter@cadcamlab.org
[samba.git] / source / smbd / connection.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    connection claim routines
5    Copyright (C) Andrew Tridgell 1998
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
25 extern fstring remote_machine;
26 static TDB_CONTEXT *tdb;
27
28 extern int DEBUGLEVEL;
29
30 #ifdef WITH_UTMP
31 static void utmp_yield(pid_t pid, const connection_struct *conn);
32 static void utmp_claim(const struct connections_data *crec, const connection_struct *conn);
33 #endif
34
35 /****************************************************************************
36 delete a connection record
37 ****************************************************************************/
38 BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
39 {
40         struct connections_key key;
41         TDB_DATA kbuf;
42
43         if (!tdb) return False;
44
45         DEBUG(3,("Yielding connection to %s\n",name));
46
47         ZERO_STRUCT(key);
48         key.pid = getpid();
49         if (conn) key.cnum = conn->cnum;
50         fstrcpy(key.name, name);
51
52         kbuf.dptr = (char *)&key;
53         kbuf.dsize = sizeof(key);
54
55         tdb_delete(tdb, kbuf);
56
57 #ifdef WITH_UTMP
58         if(conn)
59                 utmp_yield(key.pid, conn);
60 #endif
61
62         return(True);
63 }
64
65
66 /****************************************************************************
67 claim an entry in the connections database
68 ****************************************************************************/
69 BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOOL Clear)
70 {
71         struct connections_key key;
72         struct connections_data crec;
73         TDB_DATA kbuf, dbuf;
74         extern int Client;
75
76         if (max_connections <= 0)
77                 return(True);
78
79         if (!tdb) {
80                 tdb = tdb_open(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST, 
81                                O_RDWR | O_CREAT, 0644);
82         }
83         if (!tdb) return False;
84
85         DEBUG(5,("claiming %s %d\n",name,max_connections));
86
87         ZERO_STRUCT(key);
88         key.pid = getpid();
89         key.cnum = conn?conn->cnum:-1;
90         fstrcpy(key.name, name);
91
92         kbuf.dptr = (char *)&key;
93         kbuf.dsize = sizeof(key);
94
95         /* fill in the crec */
96         ZERO_STRUCT(crec);
97         crec.magic = 0x280267;
98         crec.pid = getpid();
99         crec.cnum = conn?conn->cnum:-1;
100         if (conn) {
101                 crec.uid = conn->uid;
102                 crec.gid = conn->gid;
103                 StrnCpy(crec.name,
104                         lp_servicename(SNUM(conn)),sizeof(crec.name)-1);
105         }
106         crec.start = time(NULL);
107         
108         StrnCpy(crec.machine,remote_machine,sizeof(crec.machine)-1);
109         StrnCpy(crec.addr,conn?conn->client_address:client_addr(Client),sizeof(crec.addr)-1);
110
111         dbuf.dptr = (char *)&crec;
112         dbuf.dsize = sizeof(crec);
113
114         if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) return False;
115
116 #ifdef WITH_UTMP
117         if (conn)
118             utmp_claim(&crec, conn);
119 #endif
120
121         return True;
122 }
123
124 #ifdef WITH_UTMP
125
126 /****************************************************************************
127 Reflect connection status in utmp/wtmp files.
128         T.D.Lee@durham.ac.uk  September 1999
129
130 Hints for porting:
131         o Always attempt to use programmatic interface (pututline() etc.)
132         o The "x" (utmpx/wtmpx; HAVE_UTMPX_H) seems preferable.
133
134 OS status:
135         Solaris 2.x:  Tested on 2.6 and 2.7; should be OK on other flavours.
136                 T.D.Lee@durham.ac.uk
137         HPUX 9.x:  Not tested.  Appears not to have "x".
138         IRIX 6.5:  Not tested.  Appears to have "x".
139
140 Notes:
141         The 4 byte 'ut_id' component is vital to distinguish connections,
142         of which there could be several hundered or even thousand.
143         Entries seem to be printable characters, with optional NULL pads.
144
145         We need to be distinct from other entries in utmp/wtmp.
146
147         Observed things: therefore avoid them.  Add to this list please.
148         From Solaris 2.x (because that's what I have):
149                 'sN'    : run-levels; N: [0-9]
150                 'co'    : console
151                 'CC'    : arbitrary things;  C: [a-z]
152                 'rXNN'  : rlogin;  N: [0-9]; X: [0-9a-z]
153                 'tXNN'  : rlogin;  N: [0-9]; X: [0-9a-z]
154                 '/NNN'  : Solaris CDE
155                 'ftpZ'  : ftp (Z is the number 255, aka 0377, aka 0xff)
156         Mostly a record uses the same 'ut_id' in both "utmp" and "wtmp",
157         but differences have been seen.
158
159         Arbitrarily I have chosen to use a distinctive 'SM' for the
160         first two bytes.
161
162         The remaining two encode the connection number used in samba locking
163         functions "claim_connection() and "yield_connection()".  This seems
164         to be a "nicely behaved" number: starting from 0 then working up
165         looking for an available slot.
166
167 ****************************************************************************/
168
169 #include <utmp.h>
170
171 #ifdef HAVE_UTMPX_H
172 #include <utmpx.h>
173 #endif
174
175 static const char *ut_id_encstr =
176         "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
177
178 static
179 int
180 ut_id_encode(int i, char *fourbyte)
181 {
182         int nbase;
183
184         fourbyte[0] = 'S';
185         fourbyte[1] = 'M';
186
187 /*
188  * Encode remaining 2 bytes from 'i'.
189  * 'ut_id_encstr' is the character set on which modulo arithmetic is done.
190  * Example: digits would produce the base-10 numbers from '001'.
191  */
192         nbase = strlen(ut_id_encstr);
193
194         fourbyte[3] = ut_id_encstr[i % nbase];
195         i /= nbase;
196         fourbyte[2] = ut_id_encstr[i % nbase];
197         i /= nbase;
198
199         return(i);      /* 0: good; else overflow */
200 }
201
202 static int utmp_fill(struct utmp *u, const connection_struct *conn, pid_t pid, int i)
203 {
204         struct timeval timeval;
205         int rc;
206
207         pstrcpy(u->ut_user, conn->user);
208         rc = ut_id_encode(i, u->ut_id);
209         slprintf(u->ut_line, 12, "smb/%d", i);
210
211         u->ut_pid = pid;
212
213         gettimeofday(&timeval, NULL);
214         u->ut_time = timeval.tv_sec;
215
216         return(rc);
217 }
218
219 /* Default path (if possible) */
220 #ifdef  HAVE_UTMPX_H
221
222 # ifdef UTMPX_FILE
223 static char *ut_pathname = UTMPX_FILE;
224 # else
225 static char *ut_pathname = "";
226 # endif
227 # ifdef WTMPX_FILE
228 static char *wt_pathname = WTMPX_FILE;
229 # else
230 static char *wt_pathname = "";
231 # endif
232
233 #else   /* HAVE_UTMPX_H */
234
235 # ifdef UTMP_FILE
236 static char *ut_pathname = UTMP_FILE;
237 # else
238 static char *ut_pathname = "";
239 # endif
240 # ifdef WTMP_FILE
241 static char *wt_pathname = WTMP_FILE;
242 # else
243 static char *wt_pathname = "";
244 # endif
245
246 #endif  /* HAVE_UTMPX_H */
247
248 static void uw_pathname(pstring fname, const char *uw_name)
249 {
250         pstring dirname;
251
252         pstrcpy(dirname,lp_utmpdir());
253         trim_string(dirname,"","/");
254
255         /* Given directory: use it */
256         if (dirname != 0 && strlen(dirname) != 0) {
257                 pstrcpy(fname, dirname);
258                 pstrcat(fname, "/");
259                 pstrcat(fname, uw_name);
260                 return;
261         }
262
263         /* No given directory: attempt to use default paths */
264         if (uw_name[0] == 'u') {
265                 pstrcpy(fname, ut_pathname);
266                 return;
267         }
268
269         if (uw_name[0] == 'w') {
270                 pstrcpy(fname, wt_pathname);
271                 return;
272         }
273
274         pstrcpy(fname, "");
275 }
276
277 static void utmp_update(const struct utmp *u, const char *host)
278 {
279         pstring fname;
280
281 #ifdef HAVE_UTMPX_H
282         struct utmpx ux, *uxrc;
283
284         getutmpx(u, &ux);
285         if (host) {
286 #if defined(HAVE_UX_UT_SYSLEN)
287                 ux.ut_syslen = strlen(host);
288 #endif /* defined(HAVE_UX_UT_SYSLEN) */
289                 pstrcpy(ux.ut_host, host);
290         }
291
292         uw_pathname(fname, "utmpx");
293         DEBUG(2,("utmp_update: fname:%s\n", fname));
294         if (strlen(fname) != 0) {
295                 utmpxname(fname);
296         }
297         uxrc = pututxline(&ux);
298         if (uxrc == NULL) {
299                 DEBUG(2,("utmp_update: pututxline() failed\n"));
300                 return;
301         }
302
303         uw_pathname(fname, "wtmpx");
304         DEBUG(2,("utmp_update: fname:%s\n", fname));
305         if (strlen(fname) != 0) {
306                 updwtmpx(fname, &ux);
307         }
308 #else
309         uw_pathname(fname, "utmp");
310         DEBUG(2,("utmp_update: fname:%s\n", fname));
311         if (strlen(fname) != 0) {
312                 utmpname(fname);
313         }
314         pututline(u);
315
316         uw_pathname(fname, "wtmp");
317
318         /* *** Hmmm.  Appending wtmp (as distinct from overwriting utmp) has
319         me baffled.  How is it to be done? *** */
320 #endif
321 }
322
323 static void utmp_yield(pid_t pid, const connection_struct *conn)
324 {
325         struct utmp u;
326
327         if (! lp_utmp(SNUM(conn))) {
328                 DEBUG(2,("utmp_yield: lp_utmp() NULL\n"));
329                 return;
330         }
331
332         DEBUG(2,("utmp_yield: conn: user:%s cnum:%d\n",
333                  conn->user, conn->cnum));
334
335         memset((char *)&u, '\0', sizeof(struct utmp));
336         u.ut_type = DEAD_PROCESS;
337         u.ut_exit.e_termination = 0;
338         u.ut_exit.e_exit = 0;
339         if (utmp_fill(&u, conn, pid, conn->cnum) == 0) {
340                 utmp_update(&u, NULL);
341         }
342 }
343
344 static void utmp_claim(const struct connect_record *crec, const connection_struct *conn)
345 {
346         extern int Client;
347         struct utmp u;
348
349         if (conn == NULL) {
350                 DEBUG(2,("utmp_claim: conn NULL\n"));
351                 return;
352         }
353
354         if (! lp_utmp(SNUM(conn))) {
355                 DEBUG(2,("utmp_claim: lp_utmp() NULL\n"));
356                 return;
357         }
358
359         DEBUG(2,("utmp_claim: conn: user:%s cnum:%d i:%d\n",
360           conn->user, conn->cnum, i));
361         DEBUG(2,("utmp_claim: crec: pid:%d, cnum:%d name:%s addr:%s mach:%s DNS:%s\n",
362           crec->pid, crec->cnum, crec->name, crec->addr, crec->machine, client_name(Client)));
363
364
365         memset((char *)&u, '\0', sizeof(struct utmp));
366         u.ut_type = USER_PROCESS;
367         if (utmp_fill(&u, conn, crec->pid, conn->cnum) == 0) {
368                 utmp_update(&u, crec->machine);
369         }
370 }
371
372 #endif