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