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 ux.ut_syslen = strlen(host);
229 pstrcpy(ux.ut_host, host);
232 pstrcpy(fname, dirname);
233 pstrcat(fname, "utmpx");
235 uxrc = pututxline(&ux);
237 DEBUG(2,("utmp_update: pututxline() failed\n"));
241 pstrcpy(fname, dirname);
242 pstrcat(fname, "wtmpx");
243 updwtmpx(fname, &ux);
245 pstrcpy(fname, dirname);
246 pstrcat(fname, "utmp");
251 pstrcpy(fname, dirname);
252 pstrcat(fname, "wtmp");
254 /* *** OK. Appending wtmp (as distinct from overwriting utmp) has
255 me baffled. How is it to be done? *** */
259 static void utmp_yield(int pid, const connection_struct *conn)
264 if (! lp_utmp(SNUM(conn))) {
265 DEBUG(2,("utmp_yield: lp_utmp() NULL\n"));
269 pstrcpy(dirname,lp_utmpdir());
270 trim_string(dirname,"","/");
271 pstrcat(dirname,"/");
273 DEBUG(2,("utmp_yield: dir:%s conn: user:%s cnum:%d i:%d\n",
274 dirname, conn->user, conn->cnum, conn->cnum));
276 memset((char *)&u, '\0', sizeof(struct utmp));
277 u.ut_type = DEAD_PROCESS;
278 u.ut_exit.e_termination = 0;
279 u.ut_exit.e_exit = 0;
280 if (utmp_fill(&u, conn, pid, conn->cnum) == 0) {
281 utmp_update(dirname, &u, NULL);
285 static void utmp_claim(const struct connections_data *crec, const connection_struct *conn)
292 DEBUG(2,("utmp_claim: conn NULL\n"));
296 if (! lp_utmp(SNUM(conn))) {
297 DEBUG(2,("utmp_claim: lp_utmp() NULL\n"));
301 pstrcpy(dirname,lp_utmpdir());
302 trim_string(dirname,"","/");
303 pstrcat(dirname,"/");
305 DEBUG(2,("utmp_claim: dir:%s conn: user:%s cnum:%d i:%d\n",
306 dirname, conn->user, conn->cnum, conn->cnum));
307 DEBUG(2,("utmp_claim: crec: pid:%d, cnum:%d name:%s addr:%s mach:%s DNS:%s\n",
308 crec->pid, crec->cnum, crec->name, crec->addr, crec->machine, client_name(Client)));
311 memset((char *)&u, '\0', sizeof(struct utmp));
312 u.ut_type = USER_PROCESS;
313 if (utmp_fill(&u, conn, crec->pid, conn->cnum) == 0) {
314 utmp_update(dirname, &u, crec->machine);