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);
61 kbuf.dptr = (char *)&key;
62 kbuf.dsize = sizeof(key);
64 tdb_delete(tdb, kbuf);
68 utmp_yield(key.pid, conn);
75 /****************************************************************************
76 claim an entry in the connections database
77 ****************************************************************************/
78 BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOOL Clear)
80 struct connections_key key;
81 struct connections_data crec;
85 tdb = tdb_open(lock_path("connections.tdb"), 0, TDB_CLEAR_IF_FIRST,
86 O_RDWR | O_CREAT, 0644);
88 if (!tdb) return False;
90 DEBUG(5,("claiming %s %d\n",name,max_connections));
93 key.pid = sys_getpid();
94 key.cnum = conn?conn->cnum:-1;
95 fstrcpy(key.name, name);
97 kbuf.dptr = (char *)&key;
98 kbuf.dsize = sizeof(key);
100 /* fill in the crec */
102 crec.magic = 0x280267;
103 crec.pid = sys_getpid();
104 crec.cnum = conn?conn->cnum:-1;
106 crec.uid = conn->uid;
107 crec.gid = conn->gid;
109 lp_servicename(SNUM(conn)),sizeof(crec.name)-1);
111 crec.start = time(NULL);
113 StrnCpy(crec.machine,remote_machine,sizeof(crec.machine)-1);
114 StrnCpy(crec.addr,conn?conn->client_address:client_addr(),sizeof(crec.addr)-1);
116 dbuf.dptr = (char *)&crec;
117 dbuf.dsize = sizeof(crec);
119 if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) return False;
123 utmp_claim(&crec, conn);
131 /****************************************************************************
132 Reflect connection status in utmp/wtmp files.
133 T.D.Lee@durham.ac.uk September 1999
135 With grateful thanks since then to many who have helped port it to
136 different operating systems. The variety of OS quirks thereby
137 uncovered is amazing...
140 o Always attempt to use programmatic interface (pututline() etc.)
141 Indeed, at present only programmatic use is supported.
142 o The only currently supported programmatic interface to "wtmp{,x}"
143 is through "updwtmp*()" routines.
144 o The "x" (utmpx/wtmpx; HAVE_UTMPX_H) seems preferable.
145 o The HAVE_* items should identify supported features.
146 o If at all possible, avoid "if defined(MY-OS)" constructions.
148 OS observations and status:
149 Almost every OS seems to have its own quirks.
152 Tested on 2.6 and 2.7; should be OK on other flavours.
154 Apparently has utmpx.h but doesn't implement.
156 Has utmpx.h, but (e.g.) no "getutmpx()". (Is this like AIX ?)
158 utmpx.h seems not to set default filenames. non-x better.
160 Not tested. Appears to have "x".
162 Not tested. Appears to lack "x".
165 "updwtmp*()" routines seem absent, so no current wtmp* support.
166 Has "ut_addr": probably trivial to implement (although remember
167 that IPv6 is coming...).
170 No "putut*()" type of interface.
171 No "ut_type" and associated defines.
172 Write files directly. Alternatively use its login(3)/logout(3).
174 Not tested. Resembles FreeBSD, but no login()/logout().
177 Should "lastlog" files, if any, be updated?
178 BSD systems (SunOS 4, FreeBSD):
179 o Prominent mention on man pages.
180 System-V (e.g. Solaris 2):
181 o No mention on man pages, even under "man -k".
182 o Has a "/var/adm/lastlog" file, but pututxline() etc. seem
184 o Despite downplaying (above), nevertheless has <lastlog.h>.
185 So perhaps UN*X "lastlog" facility is intended for tty/terminal only?
188 Each connection requires a small number (starting at 0, working up)
189 to represent the line (unum). This must be unique within and across
192 The 4 byte 'ut_id' component is vital to distinguish connections,
193 of which there could be several hundered or even thousand.
194 Entries seem to be printable characters, with optional NULL pads.
196 We need to be distinct from other entries in utmp/wtmp.
198 Observed things: therefore avoid them. Add to this list please.
199 From Solaris 2.x (because that's what I have):
200 'sN' : run-levels; N: [0-9]
202 'CC' : arbitrary things; C: [a-z]
203 'rXNN' : rlogin; N: [0-9]; X: [0-9a-z]
204 'tXNN' : rlogin; N: [0-9]; X: [0-9a-z]
206 'ftpZ' : ftp (Z is the number 255, aka 0377, aka 0xff)
207 Mostly a record uses the same 'ut_id' in both "utmp" and "wtmp",
208 but differences have been seen.
210 Arbitrarily I have chosen to use a distinctive 'SM' for the
213 The remaining two encode the "unum" (see above).
215 For "utmp consolidate" the suggestion was made to encode the pid into
216 those remaining two bytes (16 bits). But recent UNIX (e.g Solaris 8)
217 is migrating to pids > 16 bits, so we ought not to do this.
219 ****************************************************************************/
227 /* BSD systems: some may need lastlog.h (SunOS 4), some may not (FreeBSD) */
228 /* Some System-V systems (e.g. Solaris 2) declare this too. */
229 #ifdef HAVE_LASTLOG_H
233 /****************************************************************************
234 obtain/release a small number (0 upwards) unique within and across smbds
235 ****************************************************************************/
237 * Need a "small" number to represent this connection, unique within this
238 * smbd and across all smbds.
241 * Start at 0, hunt up for free, unique number "unum" by attempting to
242 * store it as a key in a tdb database:
243 * key: unum data: pid+conn
244 * Also store its inverse, ready for yield function:
245 * key: pid+conn data: unum
248 * Find key: pid+conn; data is unum; delete record
249 * Find key: unum ; delete record.
252 * The claim algorithm (a "for" loop attempting to store numbers in a tdb
253 * database) will be increasingly inefficient with larger numbers of
254 * connections. Is it possible to write a suitable primitive within tdb?
256 * However, by also storing the inverse key/data pair, we at least make
257 * the yield algorithm efficient.
260 static TDB_CONTEXT *tdb_utmp;
262 struct utmp_tdb_data {
267 static int utmp_claim_tdb(const connection_struct *conn)
269 struct utmp_tdb_data udata;
274 tdb_utmp = tdb_open(lock_path("utmp.tdb"), 0,
275 TDB_CLEAR_IF_FIRST, O_RDWR | O_CREAT, 0644);
277 if (!tdb_utmp) return(-1);
279 DEBUG(2,("utmp_claim_tdb: entered\n"));
282 udata.pid = sys_getpid();
283 udata.cnum = conn ? conn->cnum : -1;
285 dbuf.dptr = (char *) &udata;
286 dbuf.dsize = sizeof(udata);
288 /* The key is simply a number as close as possible to zero: find it */
290 /* stop loop when overflow +ve integers (a huge, busy machine!) */
291 for (i = 0; i >= 0 ; i++) {
292 kbuf.dptr = (char *) &i;
293 kbuf.dsize = sizeof(i);
295 if (tdb_store(tdb_utmp, kbuf, dbuf, TDB_INSERT) == 0) {
296 /* have successfully grabbed a free slot */
299 /* store the inverse for faster utmp_yield_tdb() */
300 tdb_store(tdb_utmp, dbuf, kbuf, TDB_INSERT);
302 break; /* Got it; escape */
305 if (slotnum < 0) { /* more connections than positive integers! */
306 DEBUG(2,("utmp_claim_tdb: failed\n"));
310 DEBUG(2,("utmp_claim_tdb: leaving with %d\n", slotnum));
315 static int utmp_yield_tdb(const connection_struct *conn)
317 struct utmp_tdb_data revkey;
325 DEBUG(2,("utmp_yield_tdb: entered\n"));
328 revkey.pid = sys_getpid();
329 revkey.cnum = conn ? conn->cnum : -1;
331 kbuf.dptr = (char *) &revkey;
332 kbuf.dsize = sizeof(revkey);
334 dbuf = tdb_fetch(tdb_utmp, kbuf);
335 if (dbuf.dptr == NULL) {
336 DEBUG(2,("utmp_yield_tdb: failed\n"));
337 return(-1); /* shouldn't happen */
340 /* Save our result */
341 slotnum = (int) dbuf.dptr;
344 tdb_delete(tdb_utmp, kbuf);
345 tdb_delete(tdb_utmp, dbuf);
348 DEBUG(2,("utmp_yield_tdb: leaving with %d\n", slotnum));
353 #if defined(HAVE_UT_UT_ID)
354 /****************************************************************************
355 encode the unique connection number into "ut_id"
356 ****************************************************************************/
357 static const char *ut_id_encstr =
358 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
362 ut_id_encode(int i, char *fourbyte)
370 * Encode remaining 2 bytes from 'i'.
371 * 'ut_id_encstr' is the character set on which modulo arithmetic is done.
372 * Example: digits would produce the base-10 numbers from '001'.
374 nbase = strlen(ut_id_encstr);
376 fourbyte[3] = ut_id_encstr[i % nbase];
378 fourbyte[2] = ut_id_encstr[i % nbase];
381 return(i); /* 0: good; else overflow */
383 #endif /* defined(HAVE_UT_UT_ID) */
387 * size small, e.g. Solaris: 12; FreeBSD: 8
388 * pattern conventions differ across systems.
389 * So take care in tweaking the template below.
390 * Arguably, this could be yet another smb.conf parameter.
392 static const char *ut_line_template =
393 #if defined(__FreeBSD__)
399 /****************************************************************************
400 Fill in a utmp (not utmpx) template
401 ****************************************************************************/
402 static int utmp_fill(struct utmp *u, const connection_struct *conn, pid_t pid,
405 #if defined(HAVE_UT_UT_TIME)
406 struct timeval timeval;
407 #endif /* defined(HAVE_UT_UT_TIME) */
408 char line_tmp[1024]; /* plenty big enough for slprintf() */
414 * Several (all?) systems seems to define one as the other.
415 * It is easier and clearer simply to let the following take its course,
416 * rather than to try to detect and optimise.
418 #if defined(HAVE_UT_UT_USER)
419 pstrcpy(u->ut_user, conn->user);
420 #endif /* defined(HAVE_UT_UT_USER) */
422 #if defined(HAVE_UT_UT_NAME)
423 pstrcpy(u->ut_name, conn->user);
424 #endif /* defined(HAVE_UT_UT_NAME) */
428 * If size limit proves troublesome, then perhaps use "ut_id_encode()".
430 * Temporary variable "line_tmp" avoids trouble:
431 * o with unwanted trailing NULL if ut_line full;
432 * o with overflow if ut_line would be more than full.
434 memset(line_tmp, '\0', sizeof(line_tmp));
435 slprintf(line_tmp, sizeof(line_tmp), (char *) ut_line_template, i);
436 line_len = strlen(line_tmp);
437 if (line_len <= sizeof(u->ut_line)) {
438 memcpy(u->ut_line, line_tmp, sizeof(u->ut_line));
441 DEBUG(1,("utmp_fill: ut_line exceeds field length(%d > %d)\n",
442 line_len, sizeof(u->ut_line)));
446 #if defined(HAVE_UT_UT_PID)
448 #endif /* defined(HAVE_UT_UT_PID) */
452 * Some have one, some the other. Many have both, but defined (aliased).
453 * It is easier and clearer simply to let the following take its course.
454 * But note that we do the more precise ut_tv as the final assignment.
456 #if defined(HAVE_UT_UT_TIME)
457 gettimeofday(&timeval, NULL);
458 u->ut_time = timeval.tv_sec;
459 #endif /* defined(HAVE_UT_UT_TIME) */
461 #if defined(HAVE_UT_UT_TV)
462 gettimeofday(&timeval, NULL);
464 #endif /* defined(HAVE_UT_UT_TV) */
466 #if defined(HAVE_UT_UT_HOST)
468 pstrcpy(u->ut_host, host);
470 #endif /* defined(HAVE_UT_UT_HOST) */
472 #if defined(HAVE_UT_UT_ADDR)
474 * "(unsigned long) ut_addr" apparently exists on at least HP-UX 10.20.
475 * Volunteer to implement, please ...
477 #endif /* defined(HAVE_UT_UT_ADDR) */
479 #if defined(HAVE_UT_UT_ID)
480 rc = ut_id_encode(i, u->ut_id);
481 #endif /* defined(HAVE_UT_UT_ID) */
486 /****************************************************************************
487 Default paths to various {u,w}tmp{,x} files
488 ****************************************************************************/
491 static const char *ux_pathname =
492 # if defined (UTMPX_FILE)
494 # elif defined (_UTMPX_FILE)
496 # elif defined (_PATH_UTMPX)
502 static const char *wx_pathname =
503 # if defined (WTMPX_FILE)
505 # elif defined (_WTMPX_FILE)
507 # elif defined (_PATH_WTMPX)
513 #endif /* HAVE_UTMPX_H */
515 static const char *ut_pathname =
516 # if defined (UTMP_FILE)
518 # elif defined (_UTMP_FILE)
520 # elif defined (_PATH_UTMP)
526 static const char *wt_pathname =
527 # if defined (WTMP_FILE)
529 # elif defined (_WTMP_FILE)
531 # elif defined (_PATH_WTMP)
537 /* BSD-like systems might want "lastlog" support. */
538 /* *** Not yet implemented */
539 #ifndef HAVE_PUTUTLINE /* see "pututline_my()" */
540 static const char *ll_pathname =
541 # if defined (_PATH_LASTLOG) /* what other names (if any?) */
545 # endif /* _PATH_LASTLOG */
546 #endif /* HAVE_PUTUTLINE */
549 * Get name of {u,w}tmp{,x} file.
550 * return: fname contains filename
551 * Possibly empty if this code not yet ported to this system.
553 * utmp{,x}: try "utmp dir", then default (a define)
554 * wtmp{,x}: try "wtmp dir", then "utmp dir", then default (a define)
556 static void uw_pathname(pstring fname, const char *uw_name, const char *uw_default)
560 pstrcpy(dirname, "");
562 /* For w-files, first look for explicit "wtmp dir" */
563 if (uw_name[0] == 'w') {
564 pstrcpy(dirname,lp_wtmpdir());
565 trim_string(dirname,"","/");
568 /* For u-files and non-explicit w-dir, look for "utmp dir" */
569 if (dirname == 0 || strlen(dirname) == 0) {
570 pstrcpy(dirname,lp_utmpdir());
571 trim_string(dirname,"","/");
574 /* If explicit directory above, use it */
575 if (dirname != 0 && strlen(dirname) != 0) {
576 pstrcpy(fname, dirname);
578 pstrcat(fname, uw_name);
582 /* No explicit directory: attempt to use default paths */
583 if (strlen(uw_default) == 0) {
584 /* No explicit setting, no known default.
585 * Has it yet been ported to this OS?
587 DEBUG(2,("uw_pathname: unable to determine pathname\n"));
589 pstrcpy(fname, uw_default);
592 #ifndef HAVE_PUTUTLINE
593 /****************************************************************************
594 Update utmp file directly. No subroutine interface: probably a BSD system.
595 ****************************************************************************/
596 static void pututline_my(pstring uname, struct utmp *u, BOOL claim)
598 DEBUG(1,("pututline_my: not yet implemented\n"));
599 /* BSD implementor: may want to consider (or not) adjusting "lastlog" */
601 #endif /* HAVE_PUTUTLINE */
604 /****************************************************************************
605 Update wtmp file directly. No subroutine interface: probably a BSD system.
606 Credit: Michail Vidiassov <master@iaas.msu.ru>
607 ****************************************************************************/
608 static void updwtmp_my(pstring wname, struct utmp *u, BOOL claim)
616 * may use empty ut_name to distinguish a logout record.
618 * May need "if defined(SUNOS4)" etc. around some of these,
619 * but try to avoid if possible.
622 * man page indicates ut_name and ut_host both NULL
624 * man page appears not to specify (hints non-NULL)
625 * A correspondent suggest at least ut_name should be NULL
627 memset((char *)&(u->ut_name), '\0', sizeof(u->ut_name));
628 memset((char *)&(u->ut_host), '\0', sizeof(u->ut_host));
630 /* Stolen from logwtmp function in libutil.
631 * May be more locking/blocking is needed?
633 if ((fd = open(wname, O_WRONLY|O_APPEND, 0)) < 0)
635 if (fstat(fd, &buf) == 0) {
636 if (write(fd, (char *)u, sizeof(struct utmp)) != sizeof(struct utmp))
637 (void) ftruncate(fd, buf.st_size);
641 #endif /* HAVE_UPDWTMP */
643 /****************************************************************************
644 Update via utmp/wtmp (not utmpx/wtmpx)
645 ****************************************************************************/
646 static void utmp_nox_update(struct utmp *u, pstring host, BOOL claim)
648 pstring uname, wname;
649 #if defined(PUTUTLINE_RETURNS_UTMP)
651 #endif /* PUTUTLINE_RETURNS_UTMP */
653 uw_pathname(uname, "utmp", ut_pathname);
654 DEBUG(2,("utmp_nox_update: uname:%s\n", uname));
656 #ifdef HAVE_PUTUTLINE
657 if (strlen(uname) != 0) {
661 # if defined(PUTUTLINE_RETURNS_UTMP)
666 DEBUG(2,("utmp_nox_update: pututline() failed\n"));
669 # else /* PUTUTLINE_RETURNS_UTMP */
673 # endif /* PUTUTLINE_RETURNS_UTMP */
675 #else /* HAVE_PUTUTLINE */
676 if (strlen(uname) != 0) {
677 pututline_my(uname, u, claim);
679 #endif /* HAVE_PUTUTLINE */
681 uw_pathname(wname, "wtmp", wt_pathname);
682 DEBUG(2,("utmp_nox_update: wname:%s\n", wname));
683 if (strlen(wname) != 0) {
687 * updwtmp() and the newer updwtmpx() may be unsymmetrical.
688 * At least one OS, Solaris 2.x declares the former in the
689 * "utmpx" (latter) file and context.
690 * In the Solaris case this is irrelevant: it has both and
691 * we always prefer the "x" case, so doesn't come here.
692 * But are there other systems, with no "x", which lack
696 updwtmp_my(wname, u, claim);
697 #endif /* HAVE_UPDWTMP */
701 /****************************************************************************
702 Update via utmpx/wtmpx (preferred) or via utmp/wtmp
703 ****************************************************************************/
704 static void utmp_update(struct utmp *u, pstring host, BOOL claim)
706 #if !defined(HAVE_UTMPX_H)
707 /* No utmpx stuff. Drop to non-x stuff */
708 utmp_nox_update(u, host, claim);
709 #elif !defined(HAVE_PUTUTXLINE)
710 /* Odd. Have utmpx.h but no "pututxline()". Drop to non-x stuff */
711 DEBUG(1,("utmp_update: have utmpx.h but no pututxline() function\n"));
712 utmp_nox_update(u, host, claim);
713 #elif !defined(HAVE_GETUTMPX)
714 /* Odd. Have utmpx.h but no "getutmpx()". Drop to non-x stuff */
715 DEBUG(1,("utmp_update: have utmpx.h but no getutmpx() function\n"));
716 utmp_nox_update(u, host, claim);
718 pstring uname, wname;
719 struct utmpx ux, *uxrc;
723 #if defined(HAVE_UX_UT_SYSLEN)
724 ux.ut_syslen = strlen(host) + 1; /* include end NULL */
725 #endif /* defined(HAVE_UX_UT_SYSLEN) */
726 pstrcpy(ux.ut_host, host);
729 uw_pathname(uname, "utmpx", ux_pathname);
730 uw_pathname(wname, "wtmpx", wx_pathname);
731 DEBUG(2,("utmp_update: uname:%s wname:%s\n", uname, wname));
733 * Check for either uname or wname being empty.
734 * Some systems, such as Redhat 6, have a "utmpx.h" which doesn't
735 * define default filenames.
736 * Also, our local installation has not provided an override.
737 * Drop to non-x method. (E.g. RH6 has good defaults in "utmp.h".)
739 if ((strlen(uname) == 0) || (strlen(wname) == 0)) {
740 utmp_nox_update(u, host, claim);
745 uxrc = pututxline(&ux);
748 DEBUG(2,("utmp_update: pututxline() failed\n"));
752 updwtmpx(wname, &ux);
754 /* Have utmpx.h but no "updwtmpx()". */
755 DEBUG(1,("utmp_update: no updwtmpx() function\n"));
756 #endif /* HAVE_UPDWTMPX */
758 #endif /* HAVE_UTMPX_H */
762 * "utmp consolidate": some background:
764 * In "utmp" files note every connection via this process.
765 * Argument "i" is simply a tty-like number we can use as-is.
767 * In "utmp" files, only note first open and final close. Keep:
768 * o count of open processes;
769 * o record value of first "i", to use as "i" in final close.
771 static int utmp_count = 0;
772 static int utmp_consolidate_conn_num;
774 /****************************************************************************
776 ****************************************************************************/
777 static void utmp_yield(pid_t pid, const connection_struct *conn)
782 if (! lp_utmp(SNUM(conn))) {
783 DEBUG(2,("utmp_yield: lp_utmp() NULL\n"));
787 i = utmp_yield_tdb(conn);
789 DEBUG(2,("utmp_yield: utmp_yield_tdb() failed\n"));
793 DEBUG(2,("utmp_yield: conn: user:%s cnum:%d i:%d (utmp_count:%d)\n",
794 conn->user, conn->cnum, i, utmp_count));
797 if (lp_utmp_consolidate()) {
798 if (utmp_count > 0) {
799 DEBUG(2,("utmp_yield: utmp consolidate: %d entries still open\n", utmp_count));
803 /* consolidate; final close: override conn_num */
804 conn_num = utmp_consolidate_conn_num;
808 memset((char *)&u, '\0', sizeof(struct utmp));
810 #if defined(HAVE_UT_UT_EXIT)
811 u.ut_exit.e_termination = 0;
812 u.ut_exit.e_exit = 0;
813 #endif /* defined(HAVE_UT_UT_EXIT) */
815 #if defined(HAVE_UT_UT_TYPE)
816 u.ut_type = DEAD_PROCESS;
817 #endif /* defined(HAVE_UT_UT_TYPE) */
819 if (utmp_fill(&u, conn, pid, conn_num, NULL) == 0) {
820 utmp_update(&u, NULL, False);
824 /****************************************************************************
826 ****************************************************************************/
827 static void utmp_claim(const struct connections_data *crec, const connection_struct *conn)
834 DEBUG(2,("utmp_claim: conn NULL\n"));
838 if (! lp_utmp(SNUM(conn))) {
839 DEBUG(2,("utmp_claim: lp_utmp() NULL\n"));
843 i = utmp_claim_tdb(conn);
845 DEBUG(2,("utmp_claim: utmp_claim_tdb() failed\n"));
849 pstrcpy(host, lp_utmp_hostname());
850 if (host == 0 || strlen(host) == 0) {
851 pstrcpy(host, crec->machine);
854 /* explicit "utmp host": expand for any "%" variables */
855 standard_sub_basic(host);
858 DEBUG(2,("utmp_claim: conn: user:%s cnum:%d i:%d (utmp_count:%d)\n",
859 conn->user, conn->cnum, i, utmp_count));
860 DEBUG(2,("utmp_claim: crec: pid:%d, cnum:%d name:%s addr:%s mach:%s DNS:%s host:%s\n",
861 crec->pid, crec->cnum, crec->name, crec->addr, crec->machine, client_name(), host));
864 if (lp_utmp_consolidate()) {
865 if (utmp_count > 1) {
866 DEBUG(2,("utmp_claim: utmp consolidate: %d entries already open\n", (utmp_count-1)));
870 /* consolidate; first open: keep record of "i" */
871 utmp_consolidate_conn_num = i;
875 memset((char *)&u, '\0', sizeof(struct utmp));
877 #if defined(HAVE_UT_UT_TYPE)
878 u.ut_type = USER_PROCESS;
879 #endif /* defined(HAVE_UT_UT_TYPE) */
881 if (utmp_fill(&u, conn, crec->pid, i, host) == 0) {
882 utmp_update(&u, host, True);
886 #endif /* WITH_UTMP */