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 static void utmp_update(const pstring dirname, const struct utmp *u, const char *host)
224 struct utmpx ux, *uxrc;
228 #if defined(HAVE_UX_UT_SYSLEN)
229 ux.ut_syslen = strlen(host);
230 #endif /* defined(HAVE_UX_UT_SYSLEN) */
231 pstrcpy(ux.ut_host, host);
234 pstrcpy(fname, dirname);
235 pstrcat(fname, "utmpx");
237 uxrc = pututxline(&ux);
239 DEBUG(2,("utmp_update: pututxline() failed\n"));
243 pstrcpy(fname, dirname);
244 pstrcat(fname, "wtmpx");
245 updwtmpx(fname, &ux);
247 pstrcpy(fname, dirname);
248 pstrcat(fname, "utmp");
253 pstrcpy(fname, dirname);
254 pstrcat(fname, "wtmp");
256 /* *** OK. Appending wtmp (as distinct from overwriting utmp) has
257 me baffled. How is it to be done? *** */
261 static void utmp_yield(int pid, const connection_struct *conn)
266 if (! lp_utmp(SNUM(conn))) {
267 DEBUG(2,("utmp_yield: lp_utmp() NULL\n"));
271 pstrcpy(dirname,lp_utmpdir());
272 trim_string(dirname,"","/");
273 pstrcat(dirname,"/");
275 DEBUG(2,("utmp_yield: dir:%s conn: user:%s cnum:%d i:%d\n",
276 dirname, conn->user, conn->cnum, conn->cnum));
278 memset((char *)&u, '\0', sizeof(struct utmp));
279 u.ut_type = DEAD_PROCESS;
280 u.ut_exit.e_termination = 0;
281 u.ut_exit.e_exit = 0;
282 if (utmp_fill(&u, conn, pid, conn->cnum) == 0) {
283 utmp_update(dirname, &u, NULL);
287 static void utmp_claim(const struct connections_data *crec, const connection_struct *conn)
294 DEBUG(2,("utmp_claim: conn NULL\n"));
298 if (! lp_utmp(SNUM(conn))) {
299 DEBUG(2,("utmp_claim: lp_utmp() NULL\n"));
303 pstrcpy(dirname,lp_utmpdir());
304 trim_string(dirname,"","/");
305 pstrcat(dirname,"/");
307 DEBUG(2,("utmp_claim: dir:%s conn: user:%s cnum:%d i:%d\n",
308 dirname, conn->user, conn->cnum, conn->cnum));
309 DEBUG(2,("utmp_claim: crec: pid:%d, cnum:%d name:%s addr:%s mach:%s DNS:%s\n",
310 crec->pid, crec->cnum, crec->name, crec->addr, crec->machine, client_name(Client)));
313 memset((char *)&u, '\0', sizeof(struct utmp));
314 u.ut_type = USER_PROCESS;
315 if (utmp_fill(&u, conn, crec->pid, conn->cnum) == 0) {
316 utmp_update(dirname, &u, crec->machine);