2 Unix SMB/Netbios implementation.
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.
25 extern fstring remote_machine;
26 static TDB_CONTEXT *tdb;
28 extern int DEBUGLEVEL;
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);
35 /****************************************************************************
36 delete a connection record
37 ****************************************************************************/
38 BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
40 struct connections_key key;
43 if (!tdb) return False;
45 DEBUG(3,("Yielding connection to %s\n",name));
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);
59 utmp_yield(key.pid, conn);
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;
76 if (max_connections <= 0)
80 tdb = tdb_open(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST,
81 O_RDWR | O_CREAT, 0644);
83 if (!tdb) return False;
85 DEBUG(5,("claiming %s %d\n",name,max_connections));
89 key.cnum = conn?conn->cnum:-1;
90 fstrcpy(key.name, name);
92 kbuf.dptr = (char *)&key;
93 kbuf.dsize = sizeof(key);
95 /* fill in the crec */
97 crec.magic = 0x280267;
99 crec.cnum = conn?conn->cnum:-1;
101 crec.uid = conn->uid;
102 crec.gid = conn->gid;
104 lp_servicename(SNUM(conn)),sizeof(crec.name)-1);
106 crec.start = time(NULL);
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);
111 dbuf.dptr = (char *)&crec;
112 dbuf.dsize = sizeof(crec);
114 if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) return False;
118 utmp_claim(&crec, conn);
126 /****************************************************************************
127 Reflect connection status in utmp/wtmp files.
128 T.D.Lee@durham.ac.uk September 1999
131 o Always attempt to use programmatic interface (pututline() etc.)
132 o The "x" (utmpx/wtmpx; HAVE_UTMPX_H) seems preferable.
135 Solaris 2.x: Tested on 2.6 and 2.7; should be OK on other flavours.
137 HPUX 9.x: Not tested. Appears not to have "x".
138 IRIX 6.5: Not tested. Appears to have "x".
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.
145 We need to be distinct from other entries in utmp/wtmp.
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]
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]
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.
159 Arbitrarily I have chosen to use a distinctive 'SM' for the
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.
167 ****************************************************************************/
175 static const char *ut_id_encstr =
176 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
180 ut_id_encode(int i, char *fourbyte)
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'.
192 nbase = strlen(ut_id_encstr);
194 fourbyte[3] = ut_id_encstr[i % nbase];
196 fourbyte[2] = ut_id_encstr[i % nbase];
199 return(i); /* 0: good; else overflow */
202 static int utmp_fill(struct utmp *u, const connection_struct *conn, pid_t pid, int i)
204 struct timeval timeval;
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);
213 gettimeofday(&timeval, NULL);
214 u->ut_time = timeval.tv_sec;
219 /* Default path (if possible) */
223 static char *ut_pathname = UTMPX_FILE;
225 static char *ut_pathname = "";
228 static char *wt_pathname = WTMPX_FILE;
230 static char *wt_pathname = "";
233 #else /* HAVE_UTMPX_H */
236 static char *ut_pathname = UTMP_FILE;
238 static char *ut_pathname = "";
241 static char *wt_pathname = WTMP_FILE;
243 static char *wt_pathname = "";
246 #endif /* HAVE_UTMPX_H */
248 static void uw_pathname(pstring fname, const char *uw_name)
252 pstrcpy(dirname,lp_utmpdir());
253 trim_string(dirname,"","/");
255 /* Given directory: use it */
256 if (dirname != 0 && strlen(dirname) != 0) {
257 pstrcpy(fname, dirname);
259 pstrcat(fname, uw_name);
263 /* No given directory: attempt to use default paths */
264 if (uw_name[0] == 'u') {
265 pstrcpy(fname, ut_pathname);
269 if (uw_name[0] == 'w') {
270 pstrcpy(fname, wt_pathname);
277 static void utmp_update(const struct utmp *u, const char *host)
282 struct utmpx ux, *uxrc;
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);
292 uw_pathname(fname, "utmpx");
293 DEBUG(2,("utmp_update: fname:%s\n", fname));
294 if (strlen(fname) != 0) {
297 uxrc = pututxline(&ux);
299 DEBUG(2,("utmp_update: pututxline() failed\n"));
303 uw_pathname(fname, "wtmpx");
304 DEBUG(2,("utmp_update: fname:%s\n", fname));
305 if (strlen(fname) != 0) {
306 updwtmpx(fname, &ux);
309 uw_pathname(fname, "utmp");
310 DEBUG(2,("utmp_update: fname:%s\n", fname));
311 if (strlen(fname) != 0) {
316 uw_pathname(fname, "wtmp");
318 /* *** Hmmm. Appending wtmp (as distinct from overwriting utmp) has
319 me baffled. How is it to be done? *** */
323 static void utmp_yield(pid_t pid, const connection_struct *conn)
327 if (! lp_utmp(SNUM(conn))) {
328 DEBUG(2,("utmp_yield: lp_utmp() NULL\n"));
332 DEBUG(2,("utmp_yield: conn: user:%s cnum:%d\n",
333 conn->user, conn->cnum));
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);
344 static void utmp_claim(const struct connect_record *crec, const connection_struct *conn)
350 DEBUG(2,("utmp_claim: conn NULL\n"));
354 if (! lp_utmp(SNUM(conn))) {
355 DEBUG(2,("utmp_claim: lp_utmp() NULL\n"));
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)));
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);