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
));
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
);
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
;
75 if (max_connections
<= 0)
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
));
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 */
96 crec
.magic
= 0x280267;
97 crec
.pid
= sys_getpid();
98 crec
.cnum
= conn
?conn
->cnum
:-1;
100 crec
.uid
= conn
->uid
;
101 crec
.gid
= conn
->gid
;
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
;
117 utmp_claim(&crec
, conn
);
125 /****************************************************************************
126 Reflect connection status in utmp/wtmp files.
127 T.D.Lee@durham.ac.uk September 1999
130 o Always attempt to use programmatic interface (pututline() etc.)
131 o The "x" (utmpx/wtmpx; HAVE_UTMPX_H) seems preferable.
134 Solaris 2.x: Tested on 2.6 and 2.7; should be OK on other flavours.
136 HPUX 9.x: Not tested. Appears not to have "x".
137 IRIX 6.5: Not tested. Appears to have "x".
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]
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]
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
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 ****************************************************************************/
174 static const char *ut_id_encstr
=
175 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
179 ut_id_encode(int i
, char *fourbyte
)
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
];
195 fourbyte
[2] = ut_id_encstr
[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
;
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
);
212 gettimeofday(&timeval
, NULL
);
213 u
->ut_time
= timeval
.tv_sec
;
218 /* Default path (if possible) */
222 static char *ut_pathname
= UTMPX_FILE
;
224 static char *ut_pathname
= "";
227 static char *wt_pathname
= WTMPX_FILE
;
229 static char *wt_pathname
= "";
232 #else /* HAVE_UTMPX_H */
235 static char *ut_pathname
= UTMP_FILE
;
237 static char *ut_pathname
= "";
240 static char *wt_pathname
= WTMP_FILE
;
242 static char *wt_pathname
= "";
245 #endif /* HAVE_UTMPX_H */
247 static void uw_pathname(pstring fname
, const char *uw_name
)
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
);
258 pstrcat(fname
, uw_name
);
262 /* No given directory: attempt to use default paths */
263 if (uw_name
[0] == 'u') {
264 pstrcpy(fname
, ut_pathname
);
268 if (uw_name
[0] == 'w') {
269 pstrcpy(fname
, wt_pathname
);
276 static void utmp_update(const struct utmp
*u
, const char *host
)
281 struct utmpx ux
, *uxrc
;
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) {
296 uxrc
= pututxline(&ux
);
298 DEBUG(2,("utmp_update: pututxline() failed\n"));
302 uw_pathname(fname
, "wtmpx");
303 DEBUG(2,("utmp_update: fname:%s\n", fname
));
304 if (strlen(fname
) != 0) {
305 updwtmpx(fname
, &ux
);
308 uw_pathname(fname
, "utmp");
309 DEBUG(2,("utmp_update: fname:%s\n", fname
));
310 if (strlen(fname
) != 0) {
315 uw_pathname(fname
, "wtmp");
317 /* *** Hmmm. Appending wtmp (as distinct from overwriting utmp) has
318 me baffled. How is it to be done? *** */
322 static void utmp_yield(pid_t pid
, const connection_struct
*conn
)
326 if (! lp_utmp(SNUM(conn
))) {
327 DEBUG(2,("utmp_yield: lp_utmp() NULL\n"));
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
)
348 DEBUG(2,("utmp_claim: conn NULL\n"));
352 if (! lp_utmp(SNUM(conn
))) {
353 DEBUG(2,("utmp_claim: lp_utmp() NULL\n"));
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
);