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
129 With grateful thanks since then to many who have helped port it to
130 different operating systems. The variety of OS quirks thereby
131 uncovered is amazing...
134 o Always attempt to use programmatic interface (pututline() etc.)
135 Indeed, at present only programmatic use is supported.
136 o The only currently supported programmatic interface to "wtmp{,x}"
137 is through "updwtmp*()" routines.
138 o The "x" (utmpx/wtmpx; HAVE_UTMPX_H) seems preferable.
139 o The HAVE_* items should identify supported features.
140 o If at all possible, avoid "if defined(MY-OS)" constructions.
142 OS observations and status:
143 Almost every OS seems to have its own quirks.
146 Tested on 2.6 and 2.7; should be OK on other flavours.
148 Apparently has utmpx.h but doesn't implement.
150 Has utmpx.h, but (e.g.) no "getutmpx()". (Is this like AIX ?)
152 utmpx.h seems not to set default filenames. non-x better.
154 Not tested. Appears to have "x".
156 Not tested. Appears to lack "x".
159 "updwtmp*()" routines seem absent, so no current wtmp* support.
160 Has "ut_addr": probably trivial to implement (although remember
161 that IPv6 is coming...).
164 No "putut*()" type of interface.
165 No "ut_type" and associated defines.
166 Write files directly. Alternatively use its login(3)/logout(3).
168 Not tested. Resembles FreeBSD, but no login()/logout().
171 Should "lastlog" files, if any, be updated?
172 BSD systems (SunOS 4, FreeBSD):
173 o Prominent mention on man pages.
174 System-V (e.g. Solaris 2):
175 o No mention on man pages, even under "man -k".
176 o Has a "/var/adm/lastlog" file, but pututxline() etc. seem
178 o Despite downplaying (above), nevertheless has <lastlog.h>.
179 So perhaps UN*X "lastlog" facility is intended for tty/terminal only?
182 Each connection requires a small number (starting at 0, working up)
183 to represent the line (unum). This must be unique within and across
186 The 4 byte 'ut_id' component is vital to distinguish connections,
187 of which there could be several hundered or even thousand.
188 Entries seem to be printable characters, with optional NULL pads.
190 We need to be distinct from other entries in utmp/wtmp.
192 Observed things: therefore avoid them. Add to this list please.
193 From Solaris 2.x (because that's what I have):
194 'sN' : run-levels; N: [0-9]
196 'CC' : arbitrary things; C: [a-z]
197 'rXNN' : rlogin; N: [0-9]; X: [0-9a-z]
198 'tXNN' : rlogin; N: [0-9]; X: [0-9a-z]
200 'ftpZ' : ftp (Z is the number 255, aka 0377, aka 0xff)
201 Mostly a record uses the same 'ut_id' in both "utmp" and "wtmp",
202 but differences have been seen.
204 Arbitrarily I have chosen to use a distinctive 'SM' for the
207 The remaining two encode the "unum" (see above).
209 For "utmp consolidate" the suggestion was made to encode the pid into
210 those remaining two bytes (16 bits). But recent UNIX (e.g Solaris 8)
211 is migrating to pids > 16 bits, so we ought not to do this.
213 ****************************************************************************/
221 /* BSD systems: some may need lastlog.h (SunOS 4), some may not (FreeBSD) */
222 /* Some System-V systems (e.g. Solaris 2) declare this too. */
223 #ifdef HAVE_LASTLOG_H
227 /****************************************************************************
228 obtain/release a small number (0 upwards) unique within and across smbds
229 ****************************************************************************/
231 * Need a "small" number to represent this connection, unique within this
232 * smbd and across all smbds.
235 * Start at 0, hunt up for free, unique number "unum" by attempting to
236 * store it as a key in a tdb database:
237 * key: unum data: pid+conn
238 * Also store its inverse, ready for yield function:
239 * key: pid+conn data: unum
242 * Find key: pid+conn; data is unum; delete record
243 * Find key: unum ; delete record.
246 * The claim algorithm (a "for" loop attempting to store numbers in a tdb
247 * database) will be increasingly inefficient with larger numbers of
248 * connections. Is it possible to write a suitable primitive within tdb?
250 * However, by also storing the inverse key/data pair, we at least make
251 * the yield algorithm efficient.
254 static TDB_CONTEXT *tdb_utmp;
256 struct utmp_tdb_data {
261 static int utmp_claim_tdb(const connection_struct *conn)
263 struct utmp_tdb_data udata;
268 tdb_utmp = tdb_open(lock_path("utmp.tdb"), 0,
269 TDB_CLEAR_IF_FIRST, O_RDWR | O_CREAT, 0644);
271 if (!tdb_utmp) return(-1);
273 DEBUG(2,("utmp_claim_tdb: entered\n"));
276 udata.pid = sys_getpid();
277 udata.cnum = conn ? conn->cnum : -1;
279 dbuf.dptr = (char *) &udata;
280 dbuf.dsize = sizeof(udata);
282 /* The key is simply a number as close as possible to zero: find it */
284 /* stop loop when overflow +ve integers (a huge, busy machine!) */
285 for (i = 0; i >= 0 ; i++) {
286 kbuf.dptr = (char *) &i;
287 kbuf.dsize = sizeof(i);
289 if (tdb_store(tdb_utmp, kbuf, dbuf, TDB_INSERT) == 0) {
290 /* have successfully grabbed a free slot */
293 /* store the inverse for faster utmp_yield_tdb() */
294 tdb_store(tdb_utmp, dbuf, kbuf, TDB_INSERT);
296 break; /* Got it; escape */
299 if (slotnum < 0) { /* more connections than positive integers! */
300 DEBUG(2,("utmp_claim_tdb: failed\n"));
304 DEBUG(2,("utmp_claim_tdb: leaving with %d\n", slotnum));
309 static int utmp_yield_tdb(const connection_struct *conn)
311 struct utmp_tdb_data revkey;
319 DEBUG(2,("utmp_yield_tdb: entered\n"));
322 revkey.pid = sys_getpid();
323 revkey.cnum = conn ? conn->cnum : -1;
325 kbuf.dptr = (char *) &revkey;
326 kbuf.dsize = sizeof(revkey);
328 dbuf = tdb_fetch(tdb_utmp, kbuf);
329 if (dbuf.dptr == NULL) {
330 DEBUG(2,("utmp_yield_tdb: failed\n"));
331 return(-1); /* shouldn't happen */
334 /* Save our result */
335 slotnum = (int) dbuf.dptr;
338 tdb_delete(tdb_utmp, kbuf);
339 tdb_delete(tdb_utmp, dbuf);
342 DEBUG(2,("utmp_yield_tdb: leaving with %d\n", slotnum));
347 #if defined(HAVE_UT_UT_ID)
348 /****************************************************************************
349 encode the unique connection number into "ut_id"
350 ****************************************************************************/
351 static const char *ut_id_encstr =
352 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
356 ut_id_encode(int i, char *fourbyte)
364 * Encode remaining 2 bytes from 'i'.
365 * 'ut_id_encstr' is the character set on which modulo arithmetic is done.
366 * Example: digits would produce the base-10 numbers from '001'.
368 nbase = strlen(ut_id_encstr);
370 fourbyte[3] = ut_id_encstr[i % nbase];
372 fourbyte[2] = ut_id_encstr[i % nbase];
375 return(i); /* 0: good; else overflow */
377 #endif /* defined(HAVE_UT_UT_ID) */
381 * size small, e.g. Solaris: 12; FreeBSD: 8
382 * pattern conventions differ across systems.
383 * So take care in tweaking the template below.
384 * Arguably, this could be yet another smb.conf parameter.
386 static const char *ut_line_template =
387 #if defined(__FreeBSD__)
393 /****************************************************************************
394 Fill in a utmp (not utmpx) template
395 ****************************************************************************/
396 static int utmp_fill(struct utmp *u, const connection_struct *conn, pid_t pid,
399 #if defined(HAVE_UT_UT_TIME)
400 struct timeval timeval;
401 #endif /* defined(HAVE_UT_UT_TIME) */
402 char line_tmp[1024]; /* plenty big enough for slprintf() */
408 * Several (all?) systems seems to define one as the other.
409 * It is easier and clearer simply to let the following take its course,
410 * rather than to try to detect and optimise.
412 #if defined(HAVE_UT_UT_USER)
413 pstrcpy(u->ut_user, conn->user);
414 #endif /* defined(HAVE_UT_UT_USER) */
416 #if defined(HAVE_UT_UT_NAME)
417 pstrcpy(u->ut_name, conn->user);
418 #endif /* defined(HAVE_UT_UT_NAME) */
422 * If size limit proves troublesome, then perhaps use "ut_id_encode()".
424 * Temporary variable "line_tmp" avoids trouble:
425 * o with unwanted trailing NULL if ut_line full;
426 * o with overflow if ut_line would be more than full.
428 memset(line_tmp, '\0', sizeof(line_tmp));
429 slprintf(line_tmp, sizeof(line_tmp), (char *) ut_line_template, i);
430 line_len = strlen(line_tmp);
431 if (line_len <= sizeof(u->ut_line)) {
432 memcpy(u->ut_line, line_tmp, sizeof(u->ut_line));
435 DEBUG(1,("utmp_fill: ut_line exceeds field length(%d > %d)\n",
436 line_len, sizeof(u->ut_line)));
440 #if defined(HAVE_UT_UT_PID)
442 #endif /* defined(HAVE_UT_UT_PID) */
446 * Some have one, some the other. Many have both, but defined (aliased).
447 * It is easier and clearer simply to let the following take its course.
448 * But note that we do the more precise ut_tv as the final assignment.
450 #if defined(HAVE_UT_UT_TIME)
451 gettimeofday(&timeval, NULL);
452 u->ut_time = timeval.tv_sec;
453 #endif /* defined(HAVE_UT_UT_TIME) */
455 #if defined(HAVE_UT_UT_TV)
456 gettimeofday(&timeval, NULL);
458 #endif /* defined(HAVE_UT_UT_TV) */
460 #if defined(HAVE_UT_UT_HOST)
462 pstrcpy(u->ut_host, host);
464 #endif /* defined(HAVE_UT_UT_HOST) */
466 #if defined(HAVE_UT_UT_ADDR)
468 * "(unsigned long) ut_addr" apparently exists on at least HP-UX 10.20.
469 * Volunteer to implement, please ...
471 #endif /* defined(HAVE_UT_UT_ADDR) */
473 #if defined(HAVE_UT_UT_ID)
474 rc = ut_id_encode(i, u->ut_id);
475 #endif /* defined(HAVE_UT_UT_ID) */
480 /****************************************************************************
481 Default paths to various {u,w}tmp{,x} files
482 ****************************************************************************/
485 static const char *ux_pathname =
486 # if defined (UTMPX_FILE)
488 # elif defined (_UTMPX_FILE)
490 # elif defined (_PATH_UTMPX)
496 static const char *wx_pathname =
497 # if defined (WTMPX_FILE)
499 # elif defined (_WTMPX_FILE)
501 # elif defined (_PATH_WTMPX)
507 #endif /* HAVE_UTMPX_H */
509 static const char *ut_pathname =
510 # if defined (UTMP_FILE)
512 # elif defined (_UTMP_FILE)
514 # elif defined (_PATH_UTMP)
520 static const char *wt_pathname =
521 # if defined (WTMP_FILE)
523 # elif defined (_WTMP_FILE)
525 # elif defined (_PATH_WTMP)
531 /* BSD-like systems might want "lastlog" support. */
532 /* *** Not yet implemented */
533 #ifndef HAVE_PUTUTLINE /* see "pututline_my()" */
534 static const char *ll_pathname =
535 # if defined (_PATH_LASTLOG) /* what other names (if any?) */
539 # endif /* _PATH_LASTLOG */
540 #endif /* HAVE_PUTUTLINE */
543 * Get name of {u,w}tmp{,x} file.
544 * return: fname contains filename
545 * Possibly empty if this code not yet ported to this system.
547 * utmp{,x}: try "utmp dir", then default (a define)
548 * wtmp{,x}: try "wtmp dir", then "utmp dir", then default (a define)
550 static void uw_pathname(pstring fname, const char *uw_name, const char *uw_default)
554 pstrcpy(dirname, "");
556 /* For w-files, first look for explicit "wtmp dir" */
557 if (uw_name[0] == 'w') {
558 pstrcpy(dirname,lp_wtmpdir());
559 trim_string(dirname,"","/");
562 /* For u-files and non-explicit w-dir, look for "utmp dir" */
563 if (dirname == 0 || strlen(dirname) == 0) {
564 pstrcpy(dirname,lp_utmpdir());
565 trim_string(dirname,"","/");
568 /* If explicit directory above, use it */
569 if (dirname != 0 && strlen(dirname) != 0) {
570 pstrcpy(fname, dirname);
572 pstrcat(fname, uw_name);
576 /* No explicit directory: attempt to use default paths */
577 if (strlen(uw_default) == 0) {
578 /* No explicit setting, no known default.
579 * Has it yet been ported to this OS?
581 DEBUG(2,("uw_pathname: unable to determine pathname\n"));
583 pstrcpy(fname, uw_default);
586 #ifndef HAVE_PUTUTLINE
587 /****************************************************************************
588 Update utmp file directly. No subroutine interface: probably a BSD system.
589 ****************************************************************************/
590 static void pututline_my(pstring uname, struct utmp *u, BOOL claim)
592 DEBUG(1,("pututline_my: not yet implemented\n"));
593 /* BSD implementor: may want to consider (or not) adjusting "lastlog" */
595 #endif /* HAVE_PUTUTLINE */
598 /****************************************************************************
599 Update wtmp file directly. No subroutine interface: probably a BSD system.
600 Credit: Michail Vidiassov <master@iaas.msu.ru>
601 ****************************************************************************/
602 static void updwtmp_my(pstring wname, struct utmp *u, BOOL claim)
610 * may use empty ut_name to distinguish a logout record.
612 * May need "if defined(SUNOS4)" etc. around some of these,
613 * but try to avoid if possible.
616 * man page indicates ut_name and ut_host both NULL
618 * man page appears not to specify (hints non-NULL)
619 * A correspondent suggest at least ut_name should be NULL
621 memset((char *)&(u->ut_name), '\0', sizeof(u->ut_name));
622 memset((char *)&(u->ut_host), '\0', sizeof(u->ut_host));
624 /* Stolen from logwtmp function in libutil.
625 * May be more locking/blocking is needed?
627 if ((fd = open(wname, O_WRONLY|O_APPEND, 0)) < 0)
629 if (fstat(fd, &buf) == 0) {
630 if (write(fd, (char *)u, sizeof(struct utmp)) != sizeof(struct utmp))
631 (void) ftruncate(fd, buf.st_size);
635 #endif /* HAVE_UPDWTMP */
637 /****************************************************************************
638 Update via utmp/wtmp (not utmpx/wtmpx)
639 ****************************************************************************/
640 static void utmp_nox_update(struct utmp *u, pstring host, BOOL claim)
642 pstring uname, wname;
643 #if defined(PUTUTLINE_RETURNS_UTMP)
645 #endif /* PUTUTLINE_RETURNS_UTMP */
647 uw_pathname(uname, "utmp", ut_pathname);
648 DEBUG(2,("utmp_nox_update: uname:%s\n", uname));
650 #ifdef HAVE_PUTUTLINE
651 if (strlen(uname) != 0) {
655 # if defined(PUTUTLINE_RETURNS_UTMP)
660 DEBUG(2,("utmp_nox_update: pututline() failed\n"));
663 # else /* PUTUTLINE_RETURNS_UTMP */
667 # endif /* PUTUTLINE_RETURNS_UTMP */
669 #else /* HAVE_PUTUTLINE */
670 if (strlen(uname) != 0) {
671 pututline_my(uname, u, claim);
673 #endif /* HAVE_PUTUTLINE */
675 uw_pathname(wname, "wtmp", wt_pathname);
676 DEBUG(2,("utmp_nox_update: wname:%s\n", wname));
677 if (strlen(wname) != 0) {
681 * updwtmp() and the newer updwtmpx() may be unsymmetrical.
682 * At least one OS, Solaris 2.x declares the former in the
683 * "utmpx" (latter) file and context.
684 * In the Solaris case this is irrelevant: it has both and
685 * we always prefer the "x" case, so doesn't come here.
686 * But are there other systems, with no "x", which lack
690 updwtmp_my(wname, u, claim);
691 #endif /* HAVE_UPDWTMP */
695 /****************************************************************************
696 Update via utmpx/wtmpx (preferred) or via utmp/wtmp
697 ****************************************************************************/
698 static void utmp_update(struct utmp *u, pstring host, BOOL claim)
700 #if !defined(HAVE_UTMPX_H)
701 /* No utmpx stuff. Drop to non-x stuff */
702 utmp_nox_update(u, host, claim);
703 #elif !defined(HAVE_PUTUTXLINE)
704 /* Odd. Have utmpx.h but no "pututxline()". Drop to non-x stuff */
705 DEBUG(1,("utmp_update: have utmpx.h but no pututxline() function\n"));
706 utmp_nox_update(u, host, claim);
707 #elif !defined(HAVE_GETUTMPX)
708 /* Odd. Have utmpx.h but no "getutmpx()". Drop to non-x stuff */
709 DEBUG(1,("utmp_update: have utmpx.h but no getutmpx() function\n"));
710 utmp_nox_update(u, host, claim);
712 pstring uname, wname;
713 struct utmpx ux, *uxrc;
717 #if defined(HAVE_UX_UT_SYSLEN)
718 ux.ut_syslen = strlen(host) + 1; /* include end NULL */
719 #endif /* defined(HAVE_UX_UT_SYSLEN) */
720 pstrcpy(ux.ut_host, host);
723 uw_pathname(uname, "utmpx", ux_pathname);
724 uw_pathname(wname, "wtmpx", wx_pathname);
725 DEBUG(2,("utmp_update: uname:%s wname:%s\n", uname, wname));
727 * Check for either uname or wname being empty.
728 * Some systems, such as Redhat 6, have a "utmpx.h" which doesn't
729 * define default filenames.
730 * Also, our local installation has not provided an override.
731 * Drop to non-x method. (E.g. RH6 has good defaults in "utmp.h".)
733 if ((strlen(uname) == 0) || (strlen(wname) == 0)) {
734 utmp_nox_update(u, host, claim);
739 uxrc = pututxline(&ux);
742 DEBUG(2,("utmp_update: pututxline() failed\n"));
746 updwtmpx(wname, &ux);
748 /* Have utmpx.h but no "updwtmpx()". */
749 DEBUG(1,("utmp_update: no updwtmpx() function\n"));
750 #endif /* HAVE_UPDWTMPX */
752 #endif /* HAVE_UTMPX_H */
756 * "utmp consolidate": some background:
758 * In "utmp" files note every connection via this process.
759 * Argument "i" is simply a tty-like number we can use as-is.
761 * In "utmp" files, only note first open and final close. Keep:
762 * o count of open processes;
763 * o record value of first "i", to use as "i" in final close.
765 static int utmp_count = 0;
766 static int utmp_consolidate_conn_num;
768 /****************************************************************************
770 ****************************************************************************/
771 static void utmp_yield(pid_t pid, const connection_struct *conn)
776 if (! lp_utmp(SNUM(conn))) {
777 DEBUG(2,("utmp_yield: lp_utmp() NULL\n"));
781 i = utmp_yield_tdb(conn);
783 DEBUG(2,("utmp_yield: utmp_yield_tdb() failed\n"));
787 DEBUG(2,("utmp_yield: conn: user:%s cnum:%d i:%d (utmp_count:%d)\n",
788 conn->user, conn->cnum, i, utmp_count));
791 if (lp_utmp_consolidate()) {
792 if (utmp_count > 0) {
793 DEBUG(2,("utmp_yield: utmp consolidate: %d entries still open\n", utmp_count));
797 /* consolidate; final close: override conn_num */
798 conn_num = utmp_consolidate_conn_num;
802 memset((char *)&u, '\0', sizeof(struct utmp));
804 #if defined(HAVE_UT_UT_EXIT)
805 u.ut_exit.e_termination = 0;
806 u.ut_exit.e_exit = 0;
807 #endif /* defined(HAVE_UT_UT_EXIT) */
809 #if defined(HAVE_UT_UT_TYPE)
810 u.ut_type = DEAD_PROCESS;
811 #endif /* defined(HAVE_UT_UT_TYPE) */
813 if (utmp_fill(&u, conn, pid, conn_num, NULL) == 0) {
814 utmp_update(&u, NULL, False);
818 /****************************************************************************
820 ****************************************************************************/
821 static void utmp_claim(const struct connections_data *crec, const connection_struct *conn)
828 DEBUG(2,("utmp_claim: conn NULL\n"));
832 if (! lp_utmp(SNUM(conn))) {
833 DEBUG(2,("utmp_claim: lp_utmp() NULL\n"));
837 i = utmp_claim_tdb(conn);
839 DEBUG(2,("utmp_claim: utmp_claim_tdb() failed\n"));
843 pstrcpy(host, lp_utmp_hostname());
844 if (host == 0 || strlen(host) == 0) {
845 pstrcpy(host, crec->machine);
848 /* explicit "utmp host": expand for any "%" variables */
849 standard_sub_basic(host);
852 DEBUG(2,("utmp_claim: conn: user:%s cnum:%d i:%d (utmp_count:%d)\n",
853 conn->user, conn->cnum, i, utmp_count));
854 DEBUG(2,("utmp_claim: crec: pid:%d, cnum:%d name:%s addr:%s mach:%s DNS:%s host:%s\n",
855 crec->pid, crec->cnum, crec->name, crec->addr, crec->machine, client_name(), host));
858 if (lp_utmp_consolidate()) {
859 if (utmp_count > 1) {
860 DEBUG(2,("utmp_claim: utmp consolidate: %d entries already open\n", (utmp_count-1)));
864 /* consolidate; first open: keep record of "i" */
865 utmp_consolidate_conn_num = i;
869 memset((char *)&u, '\0', sizeof(struct utmp));
871 #if defined(HAVE_UT_UT_TYPE)
872 u.ut_type = USER_PROCESS;
873 #endif /* defined(HAVE_UT_UT_TYPE) */
875 if (utmp_fill(&u, conn, crec->pid, i, host) == 0) {
876 utmp_update(&u, host, True);
880 #endif /* WITH_UTMP */