login_get_lastlog - nss enviornment - works in shell env, doesn't work when sshd calls it.

Anton Blajev - Valqk valqk at lozenetz.org
Wed Jan 17 19:05:34 EST 2007

Hash: SHA1

Hello to every one!

Maybe this is not exactly the right place,
but I don't know where to ask, so...

I have a FreeBSD-6-STABLE machine,
setuped with custom nss lib which reads from pgsql database.

It seems to be working just fine except
that I can't login trought ssh, when trying the normal method.
When I do
$>ssh host.com tcsh
I get logged and everything works - getpwent etc.
but with no accounting and enviornment setuped.
in the messages logs I get

after a quite hard debuging and nothing found,
I've decided to do some coding...
C isn't my strong side, I can read(and understand) code,
but I can't write good C apps....just a hacks.
I've researched and exracted the function that appears in the logs:

$>tail /var/log/message
Jan 16 23:59:01 user sshd[74154]: fatal: login_get_lastlog: Cannot find account for uid 1010
Jan 16 23:59:01 user sshd[74148]: fatal: login_init_entry: Cannot find user "test"
(the login_init_entry is there because I've turned on

PrintLastLog yes

before that it wasn't showing.

I've found a similar problem with nss_ldap in this list but there was no answer to it.
I hope I'll et one ;-)

I've extracted some fucntions from loginrec.c and at the bottom of the mail is the src.
The main idea is that I got the 'login_get_lastlog' function in a separate executable
so I can see if it's working ok and if not I can gdb it.

The interesting thing is that this app is workign just fine!
The only app where the getpwuid is not wokring is sshd and I can't understand why...
maybe it's in the nss implementation but please

gime me ANY ideas!!

Thanks and any help will be useful!

BTW, I'm _not_ subscribed to this list because I'm not C dev.
Please 'reply all' or to me personal.10q.

Have a nice day :)

[--code getpwuid.c --]

#include <sys/types.h>
#include <pwd.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

union login_netinfo {
        struct sockaddr sa;
        struct sockaddr_in sa_in;
        struct sockaddr_storage sa_storage;

 *   * logininfo structure  *
/* types - different to utmp.h 'type' macros */
/* (though set to the same value as linux, openbsd and others...) */
#define LTYPE_LOGIN    7
#define LTYPE_LOGOUT   8

/* string lengths - set very long */
#define LINFO_NAMESIZE 128
#define LINFO_HOSTSIZE 256

struct logininfo {
        char       progname[LINFO_PROGSIZE];     /* name of program (for PAM) */
        int        progname_null;
        short int  type;                         /* type of login (LTYPE_*) */
        int        pid;                          /* PID of login process */
        int        uid;                          /* UID of this user */
        char       line[LINFO_LINESIZE];         /* tty/pty name */
        char       username[LINFO_NAMESIZE];     /* login username */
        char       hostname[LINFO_HOSTSIZE];     /* remote hostname */
        /* 'exit_status' structure components */
        int        exit;                        /* process exit status */
        int        termination;                 /* process termination status */
        /* struct timeval (sys/time.h) isn't always available, if it isn't we'll
         * use time_t's value as tv_sec and set tv_usec to 0
        unsigned int tv_sec;
        unsigned int tv_usec;
        union login_netinfo hostaddr;       /* caller's host address(es) */
}; /* struct logininfo */

/* construct a new login entry */
struct logininfo *login_alloc_entry(int pid, const char *username,
                                    const char *hostname, const char *line);

/* lastlog *entry* functions fill out a logininfo */
struct logininfo *login_get_lastlog(struct logininfo *li, const int uid);

int main() {
int uid=1010;
struct passwd *pw;
struct logininfo li;
pw = getpwuid(uid);

                printf("U: %s\n",li.username);

 * Returns the time when the user last logged in.  Returns 0 if the
 * information is not available.  This must be called before record_login.
 * The host the user logged in from will be returned in buf.
get_last_login_time(uid_t uid, const char *logname,
    char *buf, size_t bufsize)
        struct logininfo li;

        login_get_lastlog(&li, uid);
        strlcpy(buf, li.hostname, bufsize);
        return (time_t)li.tv_sec;

 ** getlast_entry: Call low-level functions to retrieve the last login
 **                time.

/* take the uid in li and return the last login time */
getlast_entry(struct logininfo *li)
#else /* !USE_LASTLOG */

#if defined(DISABLE_LASTLOG)
        /* On some systems we shouldn't even try to obtain last login
         * time, e.g. AIX */
        return (0);
# elif defined(USE_WTMP) && \
    (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
        /* retrieve last login time from utmp */
        return (wtmp_get_entry(li));
# elif defined(USE_WTMPX) && \
    (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
        /* If wtmp isn't available, try wtmpx */
        return (wtmpx_get_entry(li));
# else
        /* Give up: No means of retrieving last login time */
        return (0);
# endif /* DISABLE_LASTLOG */
#endif /* USE_LASTLOG */

struct logininfo *
login_get_lastlog(struct logininfo *li, const int uid)
        struct passwd *pw;

        memset(li, '\0', sizeof(*li));
        li->uid = uid;

         * If we don't have a 'real' lastlog, we need the username to
         * reliably search wtmp(x) for the last login (see
         * wtmp_get_entry().)
        pw = getpwuid(uid);
        if (pw == NULL) {
                printf("FATAL::: %s: Cannot find account for uid %i", __func__, uid);

        /* No MIN_SIZEOF here - we absolutely *must not* truncate the
         * username (XXX - so check for trunc!) */
        strlcpy(li->username, pw->pw_name, sizeof(li->username));

        if (getlast_entry(li))
                return (li);
                return (NULL);


Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org


This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.

More information about the openssh-unix-dev mailing list