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 Return the connection tdb context (used for message send all).
37 ****************************************************************************/
39 TDB_CONTEXT *conn_tdb_ctx(void)
44 /****************************************************************************
45 delete a connection record
46 ****************************************************************************/
47 BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
49 struct connections_key key;
52 if (!tdb) return False;
54 DEBUG(3,("Yielding connection to %s\n",name));
57 key.pid = sys_getpid();
58 key.cnum = conn?conn->cnum:-1;
59 fstrcpy(key.name, name);
60 dos_to_unix(key.name, True); /* Convert key to unix-codepage */
62 kbuf.dptr = (char *)&key;
63 kbuf.dsize = sizeof(key);
65 tdb_delete(tdb, kbuf);
69 utmp_yield(key.pid, conn);
76 /****************************************************************************
77 claim an entry in the connections database
78 ****************************************************************************/
79 BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOOL Clear)
81 struct connections_key key;
82 struct connections_data crec;
86 tdb = tdb_open(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST,
87 O_RDWR | O_CREAT, 0644);
89 if (!tdb) return False;
91 DEBUG(5,("claiming %s %d\n",name,max_connections));
94 key.pid = sys_getpid();
95 key.cnum = conn?conn->cnum:-1;
96 fstrcpy(key.name, name);
97 dos_to_unix(key.name, True); /* Convert key to unix-codepage */
99 kbuf.dptr = (char *)&key;
100 kbuf.dsize = sizeof(key);
102 /* fill in the crec */
104 crec.magic = 0x280267;
105 crec.pid = sys_getpid();
106 crec.cnum = conn?conn->cnum:-1;
108 crec.uid = conn->uid;
109 crec.gid = conn->gid;
111 lp_servicename(SNUM(conn)),sizeof(crec.name)-1);
113 crec.start = time(NULL);
115 StrnCpy(crec.machine,remote_machine,sizeof(crec.machine)-1);
116 StrnCpy(crec.addr,conn?conn->client_address:client_addr(),sizeof(crec.addr)-1);
118 dbuf.dptr = (char *)&crec;
119 dbuf.dsize = sizeof(crec);
121 if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) return False;
125 utmp_claim(&crec, conn);
133 /****************************************************************************
134 Reflect connection status in utmp/wtmp files.
135 T.D.Lee@durham.ac.uk September 1999
137 With grateful thanks since then to many who have helped port it to
138 different operating systems. The variety of OS quirks thereby
139 uncovered is amazing...
142 o Always attempt to use programmatic interface (pututline() etc.)
143 Indeed, at present only programmatic use is supported.
144 o The only currently supported programmatic interface to "wtmp{,x}"
145 is through "updwtmp*()" routines.
146 o The "x" (utmpx/wtmpx; HAVE_UTMPX_H) seems preferable.
147 o The HAVE_* items should identify supported features.
148 o If at all possible, avoid "if defined(MY-OS)" constructions.
150 OS observations and status:
151 Almost every OS seems to have its own quirks.
154 Tested on 2.6 and 2.7; should be OK on other flavours.
156 Apparently has utmpx.h but doesn't implement.
158 Has utmpx.h, but (e.g.) no "getutmpx()". (Is this like AIX ?)
160 utmpx.h seems not to set default filenames. non-x better.
162 Not tested. Appears to have "x".
164 Not tested. Appears to lack "x".
167 "updwtmp*()" routines seem absent, so no current wtmp* support.
168 Has "ut_addr": probably trivial to implement (although remember
169 that IPv6 is coming...).
172 No "putut*()" type of interface.
173 No "ut_type" and associated defines.
174 Write files directly. Alternatively use its login(3)/logout(3).
176 Not tested. Resembles FreeBSD, but no login()/logout().
179 Should "lastlog" files, if any, be updated?
180 BSD systems (SunOS 4, FreeBSD):
181 o Prominent mention on man pages.
182 System-V (e.g. Solaris 2):
183 o No mention on man pages, even under "man -k".
184 o Has a "/var/adm/lastlog" file, but pututxline() etc. seem
186 o Despite downplaying (above), nevertheless has <lastlog.h>.
187 So perhaps UN*X "lastlog" facility is intended for tty/terminal only?
190 Each connection requires a small number (starting at 0, working up)
191 to represent the line (unum). This must be unique within and across
194 The 4 byte 'ut_id' component is vital to distinguish connections,
195 of which there could be several hundered or even thousand.
196 Entries seem to be printable characters, with optional NULL pads.
198 We need to be distinct from other entries in utmp/wtmp.
200 Observed things: therefore avoid them. Add to this list please.
201 From Solaris 2.x (because that's what I have):
202 'sN' : run-levels; N: [0-9]
204 'CC' : arbitrary things; C: [a-z]
205 'rXNN' : rlogin; N: [0-9]; X: [0-9a-z]
206 'tXNN' : rlogin; N: [0-9]; X: [0-9a-z]
208 'ftpZ' : ftp (Z is the number 255, aka 0377, aka 0xff)
209 Mostly a record uses the same 'ut_id' in both "utmp" and "wtmp",
210 but differences have been seen.
212 Arbitrarily I have chosen to use a distinctive 'SM' for the
215 The remaining two encode the "unum" (see above).
217 For "utmp consolidate" the suggestion was made to encode the pid into
218 those remaining two bytes (16 bits). But recent UNIX (e.g Solaris 8)
219 is migrating to pids > 16 bits, so we ought not to do this.
221 ****************************************************************************/
229 /* BSD systems: some may need lastlog.h (SunOS 4), some may not (FreeBSD) */
230 /* Some System-V systems (e.g. Solaris 2) declare this too. */
231 #ifdef HAVE_LASTLOG_H
235 /****************************************************************************
236 obtain/release a small number (0 upwards) unique within and across smbds
237 ****************************************************************************/
239 * Need a "small" number to represent this connection, unique within this
240 * smbd and across all smbds.
243 * Start at 0, hunt up for free, unique number "unum" by attempting to
244 * store it as a key in a tdb database:
245 * key: unum data: pid+conn
246 * Also store its inverse, ready for yield function:
247 * key: pid+conn data: unum
250 * Find key: pid+conn; data is unum; delete record
251 * Find key: unum ; delete record.
254 * The claim algorithm (a "for" loop attempting to store numbers in a tdb
255 * database) will be increasingly inefficient with larger numbers of
256 * connections. Is it possible to write a suitable primitive within tdb?
258 * However, by also storing the inverse key/data pair, we at least make
259 * the yield algorithm efficient.
262 static TDB_CONTEXT *tdb_utmp;
264 struct utmp_tdb_data {
269 static int utmp_claim_tdb(const connection_struct *conn)
271 struct utmp_tdb_data udata;
276 tdb_utmp = tdb_open(lock_path("utmp.tdb"), 0,
277 TDB_CLEAR_IF_FIRST, O_RDWR | O_CREAT, 0644);
279 if (!tdb_utmp) return(-1);
281 DEBUG(2,("utmp_claim_tdb: entered\n"));
284 udata.pid = sys_getpid();
285 udata.cnum = conn ? conn->cnum : -1;
287 dbuf.dptr = (char *) &udata;
288 dbuf.dsize = sizeof(udata);
290 /* The key is simply a number as close as possible to zero: find it */
292 /* stop loop when overflow +ve integers (a huge, busy machine!) */
293 for (i = 0; i >= 0 ; i++) {
294 kbuf.dptr = (char *) &i;
295 kbuf.dsize = sizeof(i);
297 if (tdb_store(tdb_utmp, kbuf, dbuf, TDB_INSERT) == 0) {
298 /* have successfully grabbed a free slot */
301 /* store the inverse for faster utmp_yield_tdb() */
302 tdb_store(tdb_utmp, dbuf, kbuf, TDB_INSERT);
304 break; /* Got it; escape */
307 if (slotnum < 0) { /* more connections than positive integers! */
308 DEBUG(2,("utmp_claim_tdb: failed\n"));
312 DEBUG(2,("utmp_claim_tdb: leaving with %d\n", slotnum));
317 static int utmp_yield_tdb(const connection_struct *conn)
319 struct utmp_tdb_data revkey;
327 DEBUG(2,("utmp_yield_tdb: entered\n"));
330 revkey.pid = sys_getpid();
331 revkey.cnum = conn ? conn->cnum : -1;
333 kbuf.dptr = (char *) &revkey;
334 kbuf.dsize = sizeof(revkey);
336 dbuf = tdb_fetch(tdb_utmp, kbuf);
337 if (dbuf.dptr == NULL) {
338 DEBUG(2,("utmp_yield_tdb: failed\n"));
339 return(-1); /* shouldn't happen */
342 /* Save our result */
343 slotnum = (int) dbuf.dptr;
346 tdb_delete(tdb_utmp, kbuf);
347 tdb_delete(tdb_utmp, dbuf);
350 DEBUG(2,("utmp_yield_tdb: leaving with %d\n", slotnum));
355 #if defined(HAVE_UT_UT_ID)
356 /****************************************************************************
357 encode the unique connection number into "ut_id"
358 ****************************************************************************/
359 static const char *ut_id_encstr =
360 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
364 ut_id_encode(int i, char *fourbyte)
372 * Encode remaining 2 bytes from 'i'.
373 * 'ut_id_encstr' is the character set on which modulo arithmetic is done.
374 * Example: digits would produce the base-10 numbers from '001'.
376 nbase = strlen(ut_id_encstr);
378 fourbyte[3] = ut_id_encstr[i % nbase];
380 fourbyte[2] = ut_id_encstr[i % nbase];
383 return(i); /* 0: good; else overflow */
385 #endif /* defined(HAVE_UT_UT_ID) */
389 * size small, e.g. Solaris: 12; FreeBSD: 8
390 * pattern conventions differ across systems.
391 * So take care in tweaking the template below.
392 * Arguably, this could be yet another smb.conf parameter.
394 static const char *ut_line_template =
395 #if defined(__FreeBSD__)
401 /****************************************************************************
402 Fill in a utmp (not utmpx) template
403 ****************************************************************************/
404 static int utmp_fill(struct utmp *u, const connection_struct *conn, pid_t pid,
407 #if defined(HAVE_UT_UT_TIME)
408 struct timeval timeval;
409 #endif /* defined(HAVE_UT_UT_TIME) */
410 char line_tmp[1024]; /* plenty big enough for slprintf() */
416 * Several (all?) systems seems to define one as the other.
417 * It is easier and clearer simply to let the following take its course,
418 * rather than to try to detect and optimise.
420 #if defined(HAVE_UT_UT_USER)
421 pstrcpy(u->ut_user, conn->user);
422 #endif /* defined(HAVE_UT_UT_USER) */
424 #if defined(HAVE_UT_UT_NAME)
425 pstrcpy(u->ut_name, conn->user);
426 #endif /* defined(HAVE_UT_UT_NAME) */
430 * If size limit proves troublesome, then perhaps use "ut_id_encode()".
432 * Temporary variable "line_tmp" avoids trouble:
433 * o with unwanted trailing NULL if ut_line full;
434 * o with overflow if ut_line would be more than full.
436 memset(line_tmp, '\0', sizeof(line_tmp));
437 slprintf(line_tmp, sizeof(line_tmp), (char *) ut_line_template, i);
438 line_len = strlen(line_tmp);
439 if (line_len <= sizeof(u->ut_line)) {
440 memcpy(u->ut_line, line_tmp, sizeof(u->ut_line));
443 DEBUG(1,("utmp_fill: ut_line exceeds field length(%d > %d)\n",
444 line_len, sizeof(u->ut_line)));
448 #if defined(HAVE_UT_UT_PID)
450 #endif /* defined(HAVE_UT_UT_PID) */
454 * Some have one, some the other. Many have both, but defined (aliased).
455 * It is easier and clearer simply to let the following take its course.
456 * But note that we do the more precise ut_tv as the final assignment.
458 #if defined(HAVE_UT_UT_TIME)
459 gettimeofday(&timeval, NULL);
460 u->ut_time = timeval.tv_sec;
461 #endif /* defined(HAVE_UT_UT_TIME) */
463 #if defined(HAVE_UT_UT_TV)
464 gettimeofday(&timeval, NULL);
466 #endif /* defined(HAVE_UT_UT_TV) */
468 #if defined(HAVE_UT_UT_HOST)
470 pstrcpy(u->ut_host, host);
472 #endif /* defined(HAVE_UT_UT_HOST) */
474 #if defined(HAVE_UT_UT_ADDR)
476 * "(unsigned long) ut_addr" apparently exists on at least HP-UX 10.20.
477 * Volunteer to implement, please ...
479 #endif /* defined(HAVE_UT_UT_ADDR) */
481 #if defined(HAVE_UT_UT_ID)
482 rc = ut_id_encode(i, u->ut_id);
483 #endif /* defined(HAVE_UT_UT_ID) */
488 /****************************************************************************
489 Default paths to various {u,w}tmp{,x} files
490 ****************************************************************************/
493 static const char *ux_pathname =
494 # if defined (UTMPX_FILE)
496 # elif defined (_UTMPX_FILE)
498 # elif defined (_PATH_UTMPX)
504 static const char *wx_pathname =
505 # if defined (WTMPX_FILE)
507 # elif defined (_WTMPX_FILE)
509 # elif defined (_PATH_WTMPX)
515 #endif /* HAVE_UTMPX_H */
517 static const char *ut_pathname =
518 # if defined (UTMP_FILE)
520 # elif defined (_UTMP_FILE)
522 # elif defined (_PATH_UTMP)
528 static const char *wt_pathname =
529 # if defined (WTMP_FILE)
531 # elif defined (_WTMP_FILE)
533 # elif defined (_PATH_WTMP)
539 /* BSD-like systems might want "lastlog" support. */
540 /* *** Not yet implemented */
541 #ifndef HAVE_PUTUTLINE /* see "pututline_my()" */
542 static const char *ll_pathname =
543 # if defined (_PATH_LASTLOG) /* what other names (if any?) */
547 # endif /* _PATH_LASTLOG */
548 #endif /* HAVE_PUTUTLINE */
551 * Get name of {u,w}tmp{,x} file.
552 * return: fname contains filename
553 * Possibly empty if this code not yet ported to this system.
555 * utmp{,x}: try "utmp dir", then default (a define)
556 * wtmp{,x}: try "wtmp dir", then "utmp dir", then default (a define)
558 static void uw_pathname(pstring fname, const char *uw_name, const char *uw_default)
562 pstrcpy(dirname, "");
564 /* For w-files, first look for explicit "wtmp dir" */
565 if (uw_name[0] == 'w') {
566 pstrcpy(dirname,lp_wtmpdir());
567 trim_string(dirname,"","/");
570 /* For u-files and non-explicit w-dir, look for "utmp dir" */
571 if (dirname == 0 || strlen(dirname) == 0) {
572 pstrcpy(dirname,lp_utmpdir());
573 trim_string(dirname,"","/");
576 /* If explicit directory above, use it */
577 if (dirname != 0 && strlen(dirname) != 0) {
578 pstrcpy(fname, dirname);
580 pstrcat(fname, uw_name);
584 /* No explicit directory: attempt to use default paths */
585 if (strlen(uw_default) == 0) {
586 /* No explicit setting, no known default.
587 * Has it yet been ported to this OS?
589 DEBUG(2,("uw_pathname: unable to determine pathname\n"));
591 pstrcpy(fname, uw_default);
594 #ifndef HAVE_PUTUTLINE
595 /****************************************************************************
596 Update utmp file directly. No subroutine interface: probably a BSD system.
597 ****************************************************************************/
598 static void pututline_my(pstring uname, struct utmp *u, BOOL claim)
600 DEBUG(1,("pututline_my: not yet implemented\n"));
601 /* BSD implementor: may want to consider (or not) adjusting "lastlog" */
603 #endif /* HAVE_PUTUTLINE */
606 /****************************************************************************
607 Update wtmp file directly. No subroutine interface: probably a BSD system.
608 Credit: Michail Vidiassov <master@iaas.msu.ru>
609 ****************************************************************************/
610 static void updwtmp_my(pstring wname, struct utmp *u, BOOL claim)
618 * may use empty ut_name to distinguish a logout record.
620 * May need "if defined(SUNOS4)" etc. around some of these,
621 * but try to avoid if possible.
624 * man page indicates ut_name and ut_host both NULL
626 * man page appears not to specify (hints non-NULL)
627 * A correspondent suggest at least ut_name should be NULL
629 memset((char *)&(u->ut_name), '\0', sizeof(u->ut_name));
630 memset((char *)&(u->ut_host), '\0', sizeof(u->ut_host));
632 /* Stolen from logwtmp function in libutil.
633 * May be more locking/blocking is needed?
635 if ((fd = open(wname, O_WRONLY|O_APPEND, 0)) < 0)
637 if (fstat(fd, &buf) == 0) {
638 if (write(fd, (char *)u, sizeof(struct utmp)) != sizeof(struct utmp))
639 (void) ftruncate(fd, buf.st_size);
643 #endif /* HAVE_UPDWTMP */
645 /****************************************************************************
646 Update via utmp/wtmp (not utmpx/wtmpx)
647 ****************************************************************************/
648 static void utmp_nox_update(struct utmp *u, pstring host, BOOL claim)
650 pstring uname, wname;
651 #if defined(PUTUTLINE_RETURNS_UTMP)
653 #endif /* PUTUTLINE_RETURNS_UTMP */
655 uw_pathname(uname, "utmp", ut_pathname);
656 DEBUG(2,("utmp_nox_update: uname:%s\n", uname));
658 #ifdef HAVE_PUTUTLINE
659 if (strlen(uname) != 0) {
663 # if defined(PUTUTLINE_RETURNS_UTMP)
668 DEBUG(2,("utmp_nox_update: pututline() failed\n"));
671 # else /* PUTUTLINE_RETURNS_UTMP */
675 # endif /* PUTUTLINE_RETURNS_UTMP */
677 #else /* HAVE_PUTUTLINE */
678 if (strlen(uname) != 0) {
679 pututline_my(uname, u, claim);
681 #endif /* HAVE_PUTUTLINE */
683 uw_pathname(wname, "wtmp", wt_pathname);
684 DEBUG(2,("utmp_nox_update: wname:%s\n", wname));
685 if (strlen(wname) != 0) {
689 * updwtmp() and the newer updwtmpx() may be unsymmetrical.
690 * At least one OS, Solaris 2.x declares the former in the
691 * "utmpx" (latter) file and context.
692 * In the Solaris case this is irrelevant: it has both and
693 * we always prefer the "x" case, so doesn't come here.
694 * But are there other systems, with no "x", which lack
698 updwtmp_my(wname, u, claim);
699 #endif /* HAVE_UPDWTMP */
703 /****************************************************************************
704 Update via utmpx/wtmpx (preferred) or via utmp/wtmp
705 ****************************************************************************/
706 static void utmp_update(struct utmp *u, pstring host, BOOL claim)
708 #if !defined(HAVE_UTMPX_H)
709 /* No utmpx stuff. Drop to non-x stuff */
710 utmp_nox_update(u, host, claim);
711 #elif !defined(HAVE_PUTUTXLINE)
712 /* Odd. Have utmpx.h but no "pututxline()". Drop to non-x stuff */
713 DEBUG(1,("utmp_update: have utmpx.h but no pututxline() function\n"));
714 utmp_nox_update(u, host, claim);
715 #elif !defined(HAVE_GETUTMPX)
716 /* Odd. Have utmpx.h but no "getutmpx()". Drop to non-x stuff */
717 DEBUG(1,("utmp_update: have utmpx.h but no getutmpx() function\n"));
718 utmp_nox_update(u, host, claim);
720 pstring uname, wname;
721 struct utmpx ux, *uxrc;
725 #if defined(HAVE_UX_UT_SYSLEN)
726 ux.ut_syslen = strlen(host) + 1; /* include end NULL */
727 #endif /* defined(HAVE_UX_UT_SYSLEN) */
728 pstrcpy(ux.ut_host, host);
731 uw_pathname(uname, "utmpx", ux_pathname);
732 uw_pathname(wname, "wtmpx", wx_pathname);
733 DEBUG(2,("utmp_update: uname:%s wname:%s\n", uname, wname));
735 * Check for either uname or wname being empty.
736 * Some systems, such as Redhat 6, have a "utmpx.h" which doesn't
737 * define default filenames.
738 * Also, our local installation has not provided an override.
739 * Drop to non-x method. (E.g. RH6 has good defaults in "utmp.h".)
741 if ((strlen(uname) == 0) || (strlen(wname) == 0)) {
742 utmp_nox_update(u, host, claim);
747 uxrc = pututxline(&ux);
750 DEBUG(2,("utmp_update: pututxline() failed\n"));
754 updwtmpx(wname, &ux);
756 /* Have utmpx.h but no "updwtmpx()". */
757 DEBUG(1,("utmp_update: no updwtmpx() function\n"));
758 #endif /* HAVE_UPDWTMPX */
760 #endif /* HAVE_UTMPX_H */
764 * "utmp consolidate": some background:
766 * In "utmp" files note every connection via this process.
767 * Argument "i" is simply a tty-like number we can use as-is.
769 * In "utmp" files, only note first open and final close. Keep:
770 * o count of open processes;
771 * o record value of first "i", to use as "i" in final close.
773 static int utmp_count = 0;
774 static int utmp_consolidate_conn_num;
776 /****************************************************************************
778 ****************************************************************************/
779 static void utmp_yield(pid_t pid, const connection_struct *conn)
784 if (! lp_utmp(SNUM(conn))) {
785 DEBUG(2,("utmp_yield: lp_utmp() NULL\n"));
789 i = utmp_yield_tdb(conn);
791 DEBUG(2,("utmp_yield: utmp_yield_tdb() failed\n"));
795 DEBUG(2,("utmp_yield: conn: user:%s cnum:%d i:%d (utmp_count:%d)\n",
796 conn->user, conn->cnum, i, utmp_count));
799 if (lp_utmp_consolidate()) {
800 if (utmp_count > 0) {
801 DEBUG(2,("utmp_yield: utmp consolidate: %d entries still open\n", utmp_count));
805 /* consolidate; final close: override conn_num */
806 conn_num = utmp_consolidate_conn_num;
810 memset((char *)&u, '\0', sizeof(struct utmp));
812 #if defined(HAVE_UT_UT_EXIT)
813 u.ut_exit.e_termination = 0;
814 u.ut_exit.e_exit = 0;
815 #endif /* defined(HAVE_UT_UT_EXIT) */
817 #if defined(HAVE_UT_UT_TYPE)
818 u.ut_type = DEAD_PROCESS;
819 #endif /* defined(HAVE_UT_UT_TYPE) */
821 if (utmp_fill(&u, conn, pid, conn_num, NULL) == 0) {
822 utmp_update(&u, NULL, False);
826 /****************************************************************************
828 ****************************************************************************/
829 static void utmp_claim(const struct connections_data *crec, const connection_struct *conn)
836 DEBUG(2,("utmp_claim: conn NULL\n"));
840 if (! lp_utmp(SNUM(conn))) {
841 DEBUG(2,("utmp_claim: lp_utmp() NULL\n"));
845 i = utmp_claim_tdb(conn);
847 DEBUG(2,("utmp_claim: utmp_claim_tdb() failed\n"));
851 pstrcpy(host, lp_utmp_hostname());
852 if (host == 0 || strlen(host) == 0) {
853 pstrcpy(host, crec->machine);
856 /* explicit "utmp host": expand for any "%" variables */
857 standard_sub_basic(host);
860 DEBUG(2,("utmp_claim: conn: user:%s cnum:%d i:%d (utmp_count:%d)\n",
861 conn->user, conn->cnum, i, utmp_count));
862 DEBUG(2,("utmp_claim: crec: pid:%d, cnum:%d name:%s addr:%s mach:%s DNS:%s host:%s\n",
863 crec->pid, crec->cnum, crec->name, crec->addr, crec->machine, client_name(), host));
866 if (lp_utmp_consolidate()) {
867 if (utmp_count > 1) {
868 DEBUG(2,("utmp_claim: utmp consolidate: %d entries already open\n", (utmp_count-1)));
872 /* consolidate; first open: keep record of "i" */
873 utmp_consolidate_conn_num = i;
877 memset((char *)&u, '\0', sizeof(struct utmp));
879 #if defined(HAVE_UT_UT_TYPE)
880 u.ut_type = USER_PROCESS;
881 #endif /* defined(HAVE_UT_UT_TYPE) */
883 if (utmp_fill(&u, conn, crec->pid, i, host) == 0) {
884 utmp_update(&u, host, True);
888 #endif /* WITH_UTMP */