[patch] PostgreSQL pdb backend

Hamish Friedlander hafriedlander at uacl.co.nz
Thu Nov 27 23:59:45 GMT 2003


Hi,

Here is a PostgreSQL passdb backend I wrote for Samba 3. It's based 
pretty heavily on the MySQL backend, and
has only seen light testing. I couldn't find any specific documentation 
on the passdb api, so I just did what the
MySQL backend did whenever I wasn't sure. The only difference is that a 
search for users is case insensitive
(without which I couldn't get Windows 98 clients to log on).

I've also included a patch to the autoconf files, but I have absolutely 
no idea how autoconf
works, so the patch is pretty dodgy (for example 
--with-pgsql-prefix=/usr is required if pg_config
is installed in /usr/bin, instead of it just being picked up automatically).

Also attached is sql you can pipe through psql to generate the default 
database.

The configuration is almost exactly the same as for MySQL, i.e.

passdb backend = pgsql:mydb

mydb:pgsql database = userdb
mydb:pgsql user = userdb_shadow
mydb:pgsql password = XXXXX

I'm not a member of the list, so you'll need to CC me for me to see any 
replies to this message.

Hope someone finds this helpful

Hamish Friedlander,
Software and Systems,
Ullrich Aluminium
-------------- next part --------------

/*
 * PostgresSQL password backend for samba
 * Copyright (C) Hamish Friedlander 2003
 * Based on MySQL backend (C) Jelmer Vernooij 2002
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 675
 * Mass Ave, Cambridge, MA 02139, USA.
 */

#include "includes.h"
#include <libpq-fe.h>

#define CONFIG_TABLE_DEFAULT				"samba"
#define CONFIG_LOGON_TIME_DEFAULT			"logon_time"
#define CONFIG_LOGOFF_TIME_DEFAULT			"logoff_time"
#define CONFIG_KICKOFF_TIME_DEFAULT			"kickoff_time"
#define CONFIG_PASS_LAST_SET_TIME_DEFAULT		"pass_last_set_time"
#define CONFIG_PASS_CAN_CHANGE_TIME_DEFAULT		"pass_can_change_time"
#define CONFIG_PASS_MUST_CHANGE_TIME_DEFAULT 		"pass_must_change_time"
#define CONFIG_USERNAME_DEFAULT 			"username"
#define CONFIG_DOMAIN_DEFAULT				"domain"
#define CONFIG_NT_USERNAME_DEFAULT  			"nt_username"
#define CONFIG_FULLNAME_DEFAULT				"nt_fullname"
#define CONFIG_HOME_DIR_DEFAULT				"home_dir"
#define CONFIG_DIR_DRIVE_DEFAULT			"dir_drive"
#define CONFIG_LOGON_SCRIPT_DEFAULT			"logon_script"
#define CONFIG_PROFILE_PATH_DEFAULT			"profile_path"
#define CONFIG_ACCT_DESC_DEFAULT			"acct_desc"
#define CONFIG_WORKSTATIONS_DEFAULT			"workstations"
#define CONFIG_UNKNOWN_STR_DEFAULT			"unknown_str"
#define CONFIG_MUNGED_DIAL_DEFAULT			"munged_dial"
#define CONFIG_USER_SID_DEFAULT				"user_sid"
#define CONFIG_GROUP_SID_DEFAULT			"group_sid"
#define CONFIG_LM_PW_DEFAULT				"lm_pw"
#define CONFIG_NT_PW_DEFAULT				"nt_pw"
#define CONFIG_PLAIN_PW_DEFAULT				"NULL"
#define CONFIG_ACCT_CTRL_DEFAULT			"acct_ctrl"
#define CONFIG_UNKNOWN_3_DEFAULT			"unknown_3"
#define CONFIG_LOGON_DIVS_DEFAULT			"logon_divs"
#define CONFIG_HOURS_LEN_DEFAULT			"hours_len"
#define CONFIG_UNKNOWN_5_DEFAULT			"unknown_5"
#define CONFIG_UNKNOWN_6_DEFAULT			"unknown_6"
#define CONFIG_HOST_DEFAULT				"localhost"
#define CONFIG_USER_DEFAULT				"samba"
#define CONFIG_PASS_DEFAULT				""
#define CONFIG_PORT_DEFAULT				"5432"
#define CONFIG_DB_DEFAULT				"samba"

/*
static int mysqlsam_debug_level = DBGC_ALL;

#undef DBGC_CLASS
#define DBGC_CLASS mysqlsam_debug_level
*/


/* handles for doing db transactions */
typedef struct pdb_pgsql_data {
  PGconn     *handle ;
  PGresult   *pwent  ;
  long        currow ;
  
  const char *location ;
} pdb_pgsql_data ;

/* Used to construct insert and update queries */

typedef struct pdb_pgsql_query {
  char update ;
  TALLOC_CTX *mem_ctx ;
  char *part1 ;
  char *part2 ;
} pdb_pgsql_query ;

#define SET_DATA(data,methods) { \
	if(!methods){ \
		DEBUG(0, ("invalid methods!\n")); \
			return NT_STATUS_INVALID_PARAMETER; \
	} \
	data = (struct pdb_pgsql_data *)methods->private_data; \
		if(!data || !(data->handle)){ \
			DEBUG(0, ("invalid handle!\n")); \
				return NT_STATUS_INVALID_HANDLE; \
		} \
}

#define SET_DATA_QUIET(data,methods) { \
	if(!methods){ \
		DEBUG(0, ("invalid methods!\n")); \
			return ; \
	} \
	data = (struct pdb_pgsql_data *)methods->private_data; \
		if(!data || !(data->handle)){ \
			DEBUG(0, ("invalid handle!\n")); \
				return ; \
		} \
}


static NTSTATUS pdb_pgsql_int_field ( struct pdb_methods *m, struct pdb_pgsql_query *q, const char *name, int value )
{
  if ( !name || strchr(name, '\'') ) return NT_STATUS_INVALID_PARAMETER ; /* This field shouldn't be set by us */
  
  if ( q->update )
  {
    q->part1 = talloc_asprintf_append( q->mem_ctx, q->part1, "%s = %d,", name, value ) ;
  }
  else
  {
    q->part1 = talloc_asprintf_append( q->mem_ctx, q->part1, "%s,", name ) ;
    q->part2 = talloc_asprintf_append( q->mem_ctx, q->part2, "%d,", value ) ;
  }
  
  return NT_STATUS_OK ;
}

static NTSTATUS pdb_pgsql_string_field (struct pdb_methods *methods, struct pdb_pgsql_query *q, const char *name, const char *value )
{
  char *esc ;
  
  if ( !name || !value || !strcmp(value, "") || strchr(name, '\'') ) return NT_STATUS_INVALID_PARAMETER ; /* This field shouldn't be set by module */
  
  /* Escape sname */
  esc = malloc(strlen(value) * 2 + 1);
  if ( !esc )
  {
    DEBUG(0, ("Can't allocate memory to store escaped name\n"));
    return NT_STATUS_NO_MEMORY; 
  }
  
  //tmp_sname = smb_xstrdup(sname);
  PQescapeString( esc, value, strlen(value) ) ;

  if ( q->update )
  {
    q->part1 = talloc_asprintf_append( q->mem_ctx, q->part1, "%s = '%s',", name, esc ) ;
  }
  else
  {
    q->part1 = talloc_asprintf_append( q->mem_ctx, q->part1, "%s,"  , name ) ;
    q->part2 = talloc_asprintf_append( q->mem_ctx, q->part2, "'%s',", esc  ) ;
  }
  
  SAFE_FREE( esc ) ;
  return NT_STATUS_OK ;
}

#define config_value( data, name, default_value ) \
  lp_parm_const_string( GLOBAL_SECTION_SNUM, (data)->location, name, default_value )

static const char *config_value_write ( pdb_pgsql_data *data, const char *name, const char *default_value )
{
  char const *v = NULL;
  char const *swrite = NULL;
  
  v = lp_parm_const_string( GLOBAL_SECTION_SNUM, data->location, name, default_value ) ;
  
  if (!v) return NULL ;
  
  swrite = strchr( v, ':' ) ;
  
  /* Default to the same field as read field */
  if ( !swrite ) return v ;
  
  swrite++;
  
  /* If the field is 0 chars long, we shouldn't write to it */
  if ( !strlen(swrite) || !strcmp(swrite, "NULL") ) return NULL ;
  
  /* Otherwise, use the additionally specified */
  return swrite ;
}

static const char *config_value_read ( pdb_pgsql_data *data, const char *name, const char *default_value )
{
  char *v = NULL ;
  char *swrite ;
  
  v = lp_parm_talloc_string( GLOBAL_SECTION_SNUM, data->location, name, default_value ) ;
  
  if (!v) return "NULL" ;
  
  swrite = strchr( v, ':' ) ;
  
  /* If no write is specified, there are no problems */
  if ( !swrite )
  {
    if ( strlen(v) == 0 ) return "NULL" ;
    else                  return (const char *)v ;
  }
  
  /* Otherwise, we have to cut the ':write_part' */
  *swrite = '\0' ;
  if (strlen(v) == 0) return "NULL" ;
  
  return (const char *)v ;
}

static long PQgetlong( PGresult *r, long row, long col )
{
  if ( PQgetisnull( r, row, col ) ) return 0 ;
  
  return atol( PQgetvalue( r, row,  col ) ) ;
}

static NTSTATUS row_to_sam_account ( PGresult *r, long row, SAM_ACCOUNT *u )
{
  pstring temp ;
  DOM_SID sid ;
  
  if ( row >= PQntuples( r ) ) return NT_STATUS_INVALID_PARAMETER ;

  pdb_set_logon_time           ( u, PQgetlong ( r, row,  0 ), PDB_SET ) ;
  pdb_set_logoff_time          ( u, PQgetlong ( r, row,  1 ), PDB_SET ) ;
  pdb_set_kickoff_time         ( u, PQgetlong ( r, row,  2 ), PDB_SET ) ;
  pdb_set_pass_last_set_time   ( u, PQgetlong ( r, row,  3 ), PDB_SET ) ;
  pdb_set_pass_can_change_time ( u, PQgetlong ( r, row,  4 ), PDB_SET ) ;
  pdb_set_pass_must_change_time( u, PQgetlong ( r, row,  5 ), PDB_SET ) ;
  pdb_set_username             ( u, PQgetvalue( r, row,  6 ), PDB_SET ) ;
  pdb_set_domain               ( u, PQgetvalue( r, row,  7 ), PDB_SET ) ;
  pdb_set_nt_username          ( u, PQgetvalue( r, row,  8 ), PDB_SET ) ;
  pdb_set_fullname             ( u, PQgetvalue( r, row,  9 ), PDB_SET ) ;
  pdb_set_homedir              ( u, PQgetvalue( r, row, 10 ), PDB_SET ) ;
  pdb_set_dir_drive            ( u, PQgetvalue( r, row, 11 ), PDB_SET ) ;
  pdb_set_logon_script         ( u, PQgetvalue( r, row, 12 ), PDB_SET ) ;
  pdb_set_profile_path         ( u, PQgetvalue( r, row, 13 ), PDB_SET ) ;
  pdb_set_acct_desc            ( u, PQgetvalue( r, row, 14 ), PDB_SET ) ;
  pdb_set_workstations         ( u, PQgetvalue( r, row, 15 ), PDB_SET ) ;
  pdb_set_unknown_str          ( u, PQgetvalue( r, row, 16 ), PDB_SET ) ;
  pdb_set_munged_dial          ( u, PQgetvalue( r, row, 17 ), PDB_SET ) ;
  
  pdb_set_acct_ctrl            ( u, PQgetlong ( r, row, 23 ), PDB_SET ) ;
  pdb_set_unknown_3            ( u, PQgetlong ( r, row, 24 ), PDB_SET ) ;
  pdb_set_logon_divs           ( u, PQgetlong ( r, row, 25 ), PDB_SET ) ;
  pdb_set_hours_len            ( u, PQgetlong ( r, row, 26 ), PDB_SET ) ;
  pdb_set_unknown_5            ( u, PQgetlong ( r, row, 27 ), PDB_SET ) ;
  pdb_set_unknown_6            ( u, PQgetlong ( r, row, 28 ), PDB_SET ) ;
  
  if ( !PQgetisnull( r, row, 18 ) ) string_to_sid( &sid, PQgetvalue( r, row, 18 ) ) ;
  pdb_set_user_sid ( u, &sid, PDB_SET ) ;
  if ( !PQgetisnull( r, row, 19 ) ) string_to_sid( &sid, PQgetvalue( r, row, 19 ) ) ;
  pdb_set_group_sid( u, &sid, PDB_SET ) ;
  
  if ( pdb_gethexpwd( PQgetvalue( r, row, 20 ), temp ), PDB_SET ) pdb_set_lanman_passwd( u, temp, PDB_SET ) ;
  if ( pdb_gethexpwd( PQgetvalue( r, row, 21 ), temp ), PDB_SET ) pdb_set_nt_passwd    ( u, temp, PDB_SET ) ;
  
  /* Only use plaintext password storage when lanman and nt are NOT used */
  if ( PQgetisnull( r, row, 20 ) || PQgetisnull( r, row, 21 ) ) pdb_set_plaintext_passwd( u, PQgetvalue( r, row, 22 ) ) ;
  
  return NT_STATUS_OK ;
}

static NTSTATUS pgsqlsam_setsampwent(struct pdb_methods *methods, BOOL update)
{
  struct pdb_pgsql_data *data ;
  char *query ;
  NTSTATUS retval ;
  
  SET_DATA( data, methods ) ;
  
  asprintf( &query,
            "SELECT %s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s FROM %s",
            config_value_read( data, "logon time column"           , CONFIG_LOGON_TIME_DEFAULT           ),
            config_value_read( data, "logoff time column"          , CONFIG_LOGOFF_TIME_DEFAULT          ),
            config_value_read( data, "kickoff time column"         , CONFIG_KICKOFF_TIME_DEFAULT         ),
            config_value_read( data, "pass last set time column"   , CONFIG_PASS_LAST_SET_TIME_DEFAULT   ),
            config_value_read( data, "pass can change time column" , CONFIG_PASS_CAN_CHANGE_TIME_DEFAULT ),
            config_value_read( data, "pass must change time column", CONFIG_PASS_MUST_CHANGE_TIME_DEFAULT),
            config_value_read( data, "username column"             , CONFIG_USERNAME_DEFAULT             ),
            config_value_read( data, "domain column"               , CONFIG_DOMAIN_DEFAULT               ),
            config_value_read( data, "nt username column"          , CONFIG_NT_USERNAME_DEFAULT          ),
            config_value_read( data, "fullname column"             , CONFIG_FULLNAME_DEFAULT             ),
            config_value_read( data, "home dir column"             , CONFIG_HOME_DIR_DEFAULT             ),
            config_value_read( data, "dir drive column"            , CONFIG_DIR_DRIVE_DEFAULT            ),
            config_value_read( data, "logon script column"         , CONFIG_LOGON_SCRIPT_DEFAULT         ),
            config_value_read( data, "profile path column"         , CONFIG_PROFILE_PATH_DEFAULT         ),
            config_value_read( data, "acct desc column"            , CONFIG_ACCT_DESC_DEFAULT            ),
            config_value_read( data, "workstations column"         , CONFIG_WORKSTATIONS_DEFAULT         ),
            config_value_read( data, "unknown string column"       , CONFIG_UNKNOWN_STR_DEFAULT          ),
            config_value_read( data, "munged dial column"          , CONFIG_MUNGED_DIAL_DEFAULT          ),
            config_value_read( data, "user sid column"             , CONFIG_USER_SID_DEFAULT             ),
            config_value_read( data, "group sid column"            , CONFIG_GROUP_SID_DEFAULT            ),
            config_value_read( data, "lanman pass column"          , CONFIG_LM_PW_DEFAULT                ),
            config_value_read( data, "nt pass column"              , CONFIG_NT_PW_DEFAULT                ),
            config_value_read( data, "plain pass column"           , CONFIG_PLAIN_PW_DEFAULT             ),
            config_value_read( data, "acct ctrl column"            , CONFIG_ACCT_CTRL_DEFAULT            ),
            config_value_read( data, "unknown 3 column"            , CONFIG_UNKNOWN_3_DEFAULT            ),
            config_value_read( data, "logon divs column"           , CONFIG_LOGON_DIVS_DEFAULT           ),
            config_value_read( data, "hours len column"            , CONFIG_HOURS_LEN_DEFAULT            ),
            config_value_read( data, "unknown 5 column"            , CONFIG_UNKNOWN_5_DEFAULT            ),
            config_value_read( data, "unknown 6 column"            , CONFIG_UNKNOWN_6_DEFAULT            ),
            config_value     ( data, "table"                       , CONFIG_TABLE_DEFAULT                )
          ) ;
  
  /* Do it */
  DEBUG( 5, ("Executing query %s\n", query) ) ;
  data->pwent  = PQexec( data->handle, query ) ;
  data->currow = 0 ;
  
  /* Result? */
  if ( data->pwent == NULL )
  {
    DEBUG( 0, ("Error executing %s, %s\n", query, PQerrorMessage( data->handle ) ) ) ;
    retval = NT_STATUS_UNSUCCESSFUL ;
  }
  else if ( PQresultStatus( data->pwent ) != PGRES_TUPLES_OK )
  {
    DEBUG( 0, ("Error executing %s, %s\n", query, PQresultErrorMessage( data->pwent ) ) ) ;
    retval = NT_STATUS_UNSUCCESSFUL ;
  }
  else
  {
    DEBUG( 5, ("pgsqlsam_setsampwent succeeded(%llu results)!\n", PQntuples(data->pwent)) ) ;
    retval = NT_STATUS_OK ;
  }
  
  SAFE_FREE(query);
  return retval ;
}

/***************************************************************
  End enumeration of the passwd list.
 ****************************************************************/

static void pgsqlsam_endsampwent(struct pdb_methods *methods)
{
  struct pdb_pgsql_data *data ; 
    
  SET_DATA_QUIET( data, methods ) ;
  
  if (data->pwent != NULL)
  {
    PQclear( data->pwent ) ;
  }
  
  data->pwent  = NULL ;
  data->currow = 0 ;
  
  DEBUG( 5, ("pgsql_endsampwent called\n") ) ;
}

/*****************************************************************
  Get one SAM_ACCOUNT from the list (next in line)
 *****************************************************************/

static NTSTATUS pgsqlsam_getsampwent( struct pdb_methods *methods, SAM_ACCOUNT *user )
{
  struct pdb_pgsql_data *data;
  NTSTATUS retval ;
  
  SET_DATA( data, methods ) ;
  
  if ( data->pwent == NULL )
  {
    DEBUG( 0, ("invalid pwent\n") ) ;
    return NT_STATUS_INVALID_PARAMETER ;
  }
  
  retval = row_to_sam_account( data->pwent, data->currow, user ) ;
  data->currow++ ;
  
  return retval ;
}

static NTSTATUS pgsqlsam_select_by_field ( struct pdb_methods *methods, SAM_ACCOUNT *user, const char *field, const char *sname, int caseinsensitive )
{
  struct pdb_pgsql_data *data ;
  
  char *esc ;
  char *query ;
  
  PGresult *result ;
  NTSTATUS retval ;

  SET_DATA(data, methods);

  if ( user == NULL )
  {
    DEBUG( 0, ("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n") ) ;
    return NT_STATUS_INVALID_PARAMETER;
  }
  
  DEBUG( 5, ("pgsqlsam_select_by_field: getting data where %s = %s(nonescaped)\n", field, sname) ) ;
  
  /* Escape sname */
  esc = malloc(strlen(sname) * 2 + 1);
  if ( !esc )
  {
    DEBUG(0, ("Can't allocate memory to store escaped name\n"));
    return NT_STATUS_NO_MEMORY; 
  }
  
  //tmp_sname = smb_xstrdup(sname);
  PQescapeString( esc, sname, strlen(sname) ) ;
  
  /* Build query */
  asprintf( &query,
            "SELECT %s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s FROM %s WHERE %s %s %s = %s '%s' %s",
            config_value_read( data, "logon time column"           , CONFIG_LOGON_TIME_DEFAULT           ),
            config_value_read( data, "logoff time column"          , CONFIG_LOGOFF_TIME_DEFAULT          ),
            config_value_read( data, "kickoff time column"         , CONFIG_KICKOFF_TIME_DEFAULT         ),
            config_value_read( data, "pass last set time column"   , CONFIG_PASS_LAST_SET_TIME_DEFAULT   ),
            config_value_read( data, "pass can change time column" , CONFIG_PASS_CAN_CHANGE_TIME_DEFAULT ),
            config_value_read( data, "pass must change time column", CONFIG_PASS_MUST_CHANGE_TIME_DEFAULT),
            config_value_read( data, "username column"             , CONFIG_USERNAME_DEFAULT             ),
            config_value_read( data, "domain column"               , CONFIG_DOMAIN_DEFAULT               ),
            config_value_read( data, "nt username column"          , CONFIG_NT_USERNAME_DEFAULT          ),
            config_value_read( data, "fullname column"             , CONFIG_FULLNAME_DEFAULT             ),
            config_value_read( data, "home dir column"             , CONFIG_HOME_DIR_DEFAULT             ),
            config_value_read( data, "dir drive column"            , CONFIG_DIR_DRIVE_DEFAULT            ),
            config_value_read( data, "logon script column"         , CONFIG_LOGON_SCRIPT_DEFAULT         ),
            config_value_read( data, "profile path column"         , CONFIG_PROFILE_PATH_DEFAULT         ),
            config_value_read( data, "acct desc column"            , CONFIG_ACCT_DESC_DEFAULT            ),
            config_value_read( data, "workstations column"         , CONFIG_WORKSTATIONS_DEFAULT         ),
            config_value_read( data, "unknown string column"       , CONFIG_UNKNOWN_STR_DEFAULT          ),
            config_value_read( data, "munged dial column"          , CONFIG_MUNGED_DIAL_DEFAULT          ),
            config_value_read( data, "user sid column"             , CONFIG_USER_SID_DEFAULT             ),
            config_value_read( data, "group sid column"            , CONFIG_GROUP_SID_DEFAULT            ),
            config_value_read( data, "lanman pass column"          , CONFIG_LM_PW_DEFAULT                ),
            config_value_read( data, "nt pass column"              , CONFIG_NT_PW_DEFAULT                ),
            config_value_read( data, "plain pass column"           , CONFIG_PLAIN_PW_DEFAULT             ),
            config_value_read( data, "acct ctrl column"            , CONFIG_ACCT_CTRL_DEFAULT            ),
            config_value_read( data, "unknown 3 column"            , CONFIG_UNKNOWN_3_DEFAULT            ),
            config_value_read( data, "logon divs column"           , CONFIG_LOGON_DIVS_DEFAULT           ),
            config_value_read( data, "hours len column"            , CONFIG_HOURS_LEN_DEFAULT            ),
            config_value_read( data, "unknown 5 column"            , CONFIG_UNKNOWN_5_DEFAULT            ),
            config_value_read( data, "unknown 6 column"            , CONFIG_UNKNOWN_6_DEFAULT            ),
            config_value     ( data, "table"                       , CONFIG_TABLE_DEFAULT                ),
            ( caseinsensitive ? "lower(" : "" ), field, ( caseinsensitive ? ")" : "" ),
            ( caseinsensitive ? "lower(" : "" ), esc  , ( caseinsensitive ? ")" : "" ) ) ;
  
  /* Do it */
  DEBUG( 5, ("Executing query %s\n", query) ) ;
  result = PQexec( data->handle, query ) ;
  
  /* Result? */
  if ( result == NULL )
  {
    DEBUG( 0, ("Error executing %s, %s\n", query, PQerrorMessage( data->handle ) ) ) ;
    retval = NT_STATUS_UNSUCCESSFUL ;
  }
  else if ( PQresultStatus( result ) != PGRES_TUPLES_OK )
  {
    DEBUG( 0, ("Error executing %s, %s\n", query, PQresultErrorMessage( result ) ) ) ;
    retval = NT_STATUS_UNSUCCESSFUL ;
  }
  else
  {
    retval = row_to_sam_account( result, 0, user ) ;
  }
  
  SAFE_FREE( esc   ) ;
  SAFE_FREE( query ) ;
  
  PQclear( result ) ;
  
  return retval ;
}

/******************************************************************
  Lookup a name in the SAM database
 ******************************************************************/

static NTSTATUS pgsqlsam_getsampwnam ( struct pdb_methods *methods, SAM_ACCOUNT *user, const char *sname )
{
  struct pdb_pgsql_data *data;
  
  SET_DATA(data, methods);
  
  if ( !sname )
  {
    DEBUG( 0, ("invalid name specified") ) ;
    return NT_STATUS_INVALID_PARAMETER;
  }
  
  return pgsqlsam_select_by_field( methods, user,
                                   config_value_read( data, "username column", CONFIG_USERNAME_DEFAULT ),
                                   sname, 1 ) ;
}


/***************************************************************************
  Search by sid
 **************************************************************************/

static NTSTATUS pgsqlsam_getsampwsid ( struct pdb_methods *methods, SAM_ACCOUNT *user, const DOM_SID *sid )
{
  struct pdb_pgsql_data *data;
  fstring sid_str;
  
  SET_DATA( data, methods ) ;
  
  sid_to_string( sid_str, sid ) ;
  
  return pgsqlsam_select_by_field( methods, user,
                                   config_value_read( data, "user sid column", CONFIG_USER_SID_DEFAULT ),
                                   sid_str, 0 ) ;
}

/***************************************************************************
  Delete a SAM_ACCOUNT
 ****************************************************************************/

static NTSTATUS pgsqlsam_delete_sam_account( struct pdb_methods *methods, SAM_ACCOUNT *sam_pass )
{
  struct pdb_pgsql_data *data ;
  
  const char *sname = pdb_get_username( sam_pass ) ;
  char *esc ;
  char *query ;
  
  PGresult *result ;
  NTSTATUS retval ;
  
  SET_DATA(data, methods);
  
  if ( !sname )
  {
    DEBUG( 0, ("invalid name specified\n") ) ;
    return NT_STATUS_INVALID_PARAMETER ;
  }
  
  /* Escape sname */
  esc = malloc(strlen(sname) * 2 + 1);
  if ( !esc )
  {
    DEBUG(0, ("Can't allocate memory to store escaped name\n"));
    return NT_STATUS_NO_MEMORY;
  }
  
  PQescapeString( esc, sname, strlen(sname) ) ;
  
  /* Make the query */
  asprintf( &query, "DELETE FROM %s WHERE %s = '%s'",
            config_value     (data, "table"          , CONFIG_TABLE_DEFAULT   ),
            config_value_read(data, "username column", CONFIG_USERNAME_DEFAULT),
            esc ) ;
  
  /* Do it */
  result = PQexec( data->handle, query ) ;
  
  if ( result == NULL )
  {
    DEBUG( 0, ("Error executing %s, %s\n", query, PQerrorMessage( data->handle ) ) ) ;
    retval = NT_STATUS_UNSUCCESSFUL ;
  }
  else if ( PQresultStatus( result ) != PGRES_COMMAND_OK )
  {
    DEBUG( 0, ("Error executing %s, %s\n", query, PQresultErrorMessage( result ) ) ) ;
    retval = NT_STATUS_UNSUCCESSFUL ;
  }
  else
  {
    DEBUG( 5, ("User '%s' deleted\n", sname) ) ;
    retval = NT_STATUS_OK ;
  }
  
  SAFE_FREE( esc       ) ;
  SAFE_FREE( query     ) ;
  
  return retval ;
}

static NTSTATUS pgsqlsam_replace_sam_account( struct pdb_methods *methods, const SAM_ACCOUNT *newpwd, char isupdate )
{
  pstring temp ;
  struct pdb_pgsql_data *data ;
  pdb_pgsql_query query ;
  fstring sid_str ;
  PGresult *result ;
  
  if ( !methods )
  {
    DEBUG( 0, ("invalid methods!\n") ) ;
    return NT_STATUS_INVALID_PARAMETER ;
  }
  
  data = (struct pdb_pgsql_data *) methods->private_data ;
  
  if ( data == NULL || data->handle == NULL )
  {
    DEBUG( 0, ("invalid handle!\n") ) ;
    return NT_STATUS_INVALID_HANDLE ;
  }
  
  query.update = isupdate ;
  
  /* I know this is somewhat overkill but only the talloc 
   * functions have asprint_append and the 'normal' asprintf 
   * is a GNU extension */
  
  query.mem_ctx = talloc_init( "pgsqlsam_replace_sam_account" ) ;
  
  query.part2 = talloc_asprintf( query.mem_ctx, "%s", "" ) ;
  if ( query.update )
  {
    query.part1 = talloc_asprintf( query.mem_ctx, "UPDATE %s SET ", config_value(data, "table", CONFIG_TABLE_DEFAULT) ) ;
  }
  else
  {
    query.part1 = talloc_asprintf( query.mem_ctx, "INSERT INTO %s (", config_value(data, "table", CONFIG_TABLE_DEFAULT) ) ;
  }
  
  pdb_pgsql_int_field( methods, &query, config_value_write(data, "acct ctrl column", CONFIG_ACCT_CTRL_DEFAULT), pdb_get_acct_ctrl(newpwd) ) ;

  if ( pdb_get_init_flags(newpwd, PDB_LOGONTIME) != PDB_DEFAULT )
    pdb_pgsql_int_field( methods, &query,
                         config_value_write( data, "logon time column", CONFIG_LOGON_TIME_DEFAULT ),
                         pdb_get_logon_time(newpwd) ) ;
  
  if ( pdb_get_init_flags(newpwd, PDB_LOGOFFTIME) != PDB_DEFAULT )
    pdb_pgsql_int_field( methods, &query, 
                         config_value_write( data, "logoff time column", CONFIG_LOGOFF_TIME_DEFAULT ),
                         pdb_get_logoff_time(newpwd) ) ;
  
  if (pdb_get_init_flags(newpwd, PDB_KICKOFFTIME) != PDB_DEFAULT)
    pdb_pgsql_int_field( methods, &query,
                         config_value_write( data, "kickoff time column", CONFIG_KICKOFF_TIME_DEFAULT ),
                         pdb_get_kickoff_time(newpwd) ) ;
  
  if (pdb_get_init_flags(newpwd, PDB_CANCHANGETIME) != PDB_DEFAULT)
    pdb_pgsql_int_field( methods, &query,
                         config_value_write( data, "pass can change time column", CONFIG_PASS_CAN_CHANGE_TIME_DEFAULT),
                         pdb_get_pass_can_change_time(newpwd) ) ;
  
  if (pdb_get_init_flags(newpwd, PDB_MUSTCHANGETIME) != PDB_DEFAULT)
    pdb_pgsql_int_field( methods, &query,
                         config_value_write( data, "pass must change time column", CONFIG_PASS_MUST_CHANGE_TIME_DEFAULT ),
                         pdb_get_pass_must_change_time(newpwd) ) ;
  
  if ( pdb_get_pass_last_set_time(newpwd) )
    pdb_pgsql_int_field( methods, &query,
                         config_value_write( data, "pass last set time column", CONFIG_PASS_LAST_SET_TIME_DEFAULT ),
                         pdb_get_pass_last_set_time(newpwd) ) ;
  
  if ( pdb_get_hours_len(newpwd) )
    pdb_pgsql_int_field( methods, &query,
                         config_value_write( data, "hours len column", CONFIG_HOURS_LEN_DEFAULT ),
                         pdb_get_hours_len(newpwd) ) ;
  
  if ( pdb_get_logon_divs(newpwd) )
    pdb_pgsql_int_field( methods, &query,
                         config_value_write( data, "logon divs column", CONFIG_LOGON_DIVS_DEFAULT ),
                         pdb_get_logon_divs(newpwd) ) ;
  
  pdb_pgsql_string_field( methods, &query,
                          config_value_write( data, "user sid column", CONFIG_USER_SID_DEFAULT ),
                          sid_to_string( sid_str, pdb_get_user_sid(newpwd) ) ) ;
  
  pdb_pgsql_string_field( methods, &query,
                          config_value_write( data, "group sid column", CONFIG_GROUP_SID_DEFAULT ),
                          sid_to_string(sid_str, pdb_get_group_sid(newpwd) ) ) ;
  
  pdb_pgsql_string_field( methods, &query,
                          config_value_write( data, "username column", CONFIG_USERNAME_DEFAULT ),
                          pdb_get_username(newpwd) ) ;
  
  pdb_pgsql_string_field( methods, &query,
                          config_value_write( data, "domain column", CONFIG_DOMAIN_DEFAULT ),
                          pdb_get_domain(newpwd) ) ;
  
  pdb_pgsql_string_field( methods, &query,
                          config_value_write( data, "nt username column", CONFIG_NT_USERNAME_DEFAULT ),
                          pdb_get_nt_username(newpwd) ) ;
  
  pdb_pgsql_string_field( methods, &query,
                          config_value_write( data, "fullname column", CONFIG_FULLNAME_DEFAULT ),
                          pdb_get_fullname(newpwd) ) ;
  
  pdb_pgsql_string_field( methods, &query,
                          config_value_write( data, "logon script column", CONFIG_LOGON_SCRIPT_DEFAULT ),
                          pdb_get_logon_script(newpwd) ) ;
  
  pdb_pgsql_string_field( methods, &query,
                          config_value_write( data, "profile path column", CONFIG_PROFILE_PATH_DEFAULT ),
                          pdb_get_profile_path(newpwd) ) ;
  
  pdb_pgsql_string_field( methods, &query,
                          config_value_write( data, "dir drive column", CONFIG_DIR_DRIVE_DEFAULT ),
                          pdb_get_dir_drive(newpwd) ) ;
  
  pdb_pgsql_string_field( methods, &query,
                          config_value_write( data, "home dir column", CONFIG_HOME_DIR_DEFAULT ),
                          pdb_get_homedir(newpwd) ) ;
  
  pdb_pgsql_string_field( methods, &query,
                          config_value_write( data, "workstations column", CONFIG_WORKSTATIONS_DEFAULT ),
                          pdb_get_workstations(newpwd) ) ;
  
  pdb_pgsql_string_field( methods, &query,
                          config_value_write( data, "unknown string column", CONFIG_UNKNOWN_STR_DEFAULT ),
                          pdb_get_workstations(newpwd) ) ;
  
  pdb_sethexpwd( temp, pdb_get_lanman_passwd(newpwd), pdb_get_acct_ctrl(newpwd) ) ;
  pdb_pgsql_string_field( methods, &query,
                          config_value_write( data, "lanman pass column", CONFIG_LM_PW_DEFAULT ),
                          temp ) ;
  
  pdb_sethexpwd( temp, pdb_get_nt_passwd(newpwd), pdb_get_acct_ctrl(newpwd) ) ;
  pdb_pgsql_string_field( methods, &query,
                          config_value_write( data, "nt pass column", CONFIG_NT_PW_DEFAULT ),
                          temp ) ;

  if ( query.update )
  {
    query.part1[strlen(query.part1) - 1] = '\0';
    query.part1 = talloc_asprintf_append( query.mem_ctx, query.part1,
                                          " WHERE %s = '%s'",
                                          config_value_read( data, "user sid column", CONFIG_USER_SID_DEFAULT ),
                                          sid_to_string( sid_str, pdb_get_user_sid (newpwd) ) ) ;
  }
  else
  {
    query.part2[strlen(query.part2) - 1] = ')';
    query.part1[strlen(query.part1) - 1] = ')';
    query.part1 = talloc_asprintf_append( query.mem_ctx, query.part1,
                                          " VALUES (%s",
                                          query.part2 ) ;
  }
  
  DEBUG( 0, ("%s\n", query.part1) ) ;
  
  result = PQexec( data->handle, query.part1 ) ;
  
  /* Execute the query */
  if ( result == NULL )
  {
    DEBUG( 0, ("Error executing %s, %s\n", query.part1, PQerrorMessage( data->handle ) ) ) ;
    return NT_STATUS_INVALID_PARAMETER;
  }
  else if ( PQresultStatus( result ) != PGRES_COMMAND_OK )
  {
    DEBUG( 0, ("Error executing %s, %s\n", query.part1, PQresultErrorMessage( result ) ) ) ;
    return NT_STATUS_INVALID_PARAMETER;
  }
  
  talloc_destroy( query.mem_ctx ) ;
  return NT_STATUS_OK;
}

static NTSTATUS pgsqlsam_add_sam_account ( struct pdb_methods *methods, SAM_ACCOUNT *newpwd )
{
  return pgsqlsam_replace_sam_account( methods, newpwd, 0 ) ;
}

static NTSTATUS pgsqlsam_update_sam_account ( struct pdb_methods *methods, SAM_ACCOUNT *newpwd )
{
  return pgsqlsam_replace_sam_account( methods, newpwd, 1 ) ;
}

static NTSTATUS pgsqlsam_init ( struct pdb_context *pdb_context, struct pdb_methods **pdb_method, const char *location )
{
  NTSTATUS nt_status ;
  struct pdb_pgsql_data *data ;
  
  /*
  mysqlsam_debug_level = debug_add_class( "mysqlsam" ) ;
  if ( mysqlsam_debug_level == -1 )
  {
    mysqlsam_debug_level = DBGC_ALL ;
    DEBUG( 0, ("mysqlsam: Couldn't register custom debugging class!\n") ) ;
  }
  */
  
  if ( !pdb_context )
  {
    DEBUG( 0, ("invalid pdb_methods specified\n") ) ;
    return NT_STATUS_UNSUCCESSFUL;
  }
  
  if (!NT_STATUS_IS_OK
    (nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
    return nt_status;
  }
  
  (*pdb_method)->name               = "pgsqlsam" ;
  
  (*pdb_method)->setsampwent        = pgsqlsam_setsampwent ;
  (*pdb_method)->endsampwent        = pgsqlsam_endsampwent ;
  (*pdb_method)->getsampwent        = pgsqlsam_getsampwent ;
  (*pdb_method)->getsampwnam        = pgsqlsam_getsampwnam ;
  (*pdb_method)->getsampwsid        = pgsqlsam_getsampwsid ;
  (*pdb_method)->add_sam_account    = pgsqlsam_add_sam_account ;
  (*pdb_method)->update_sam_account = pgsqlsam_update_sam_account ;
  (*pdb_method)->delete_sam_account = pgsqlsam_delete_sam_account ;
  
  data = talloc( pdb_context->mem_ctx, sizeof( struct pdb_pgsql_data ) ) ;
  (*pdb_method)->private_data = data ;
  data->handle = NULL ;
  data->pwent  = NULL ;

  if ( !location )
  {
    DEBUG( 0, ("No identifier specified. Check the Samba HOWTO Collection for details\n") ) ;
    return NT_STATUS_INVALID_PARAMETER;
  }
  
  data->location = smb_xstrdup( location ) ;
  
  DEBUG
  (
    1, 
    (
      "Connecting to database server, host: %s, user: %s, password: XXXXXX, database: %s, port: %s\n",
      config_value( data, "pgsql host"    , CONFIG_HOST_DEFAULT ),
      config_value( data, "pgsql user"    , CONFIG_USER_DEFAULT ),
      config_value( data, "pgsql database", CONFIG_DB_DEFAULT   ),
      config_value( data, "pgsql port"    , CONFIG_PORT_DEFAULT )
    )
  ) ;
  
  /* Do the pgsql initialization */
  data->handle = PQsetdbLogin( 
                                config_value( data, "pgsql host"    , CONFIG_HOST_DEFAULT ),
                                config_value( data, "pgsql port"    , CONFIG_PORT_DEFAULT ),
                                NULL,
                                NULL,
                                config_value( data, "pgsql database", CONFIG_DB_DEFAULT   ),
                                config_value( data, "pgsql user"    , CONFIG_USER_DEFAULT ),
                                config_value( data, "pgsql password", CONFIG_PASS_DEFAULT )
                             ) ;
  
  if ( PQstatus( data->handle ) != CONNECTION_OK )
  {
    DEBUG( 0, ("Failed to connect to pgsql database: error: %s\n", PQerrorMessage( data->handle )) ) ;
    return NT_STATUS_UNSUCCESSFUL;
  }
  
  DEBUG( 5, ("Connected to pgsql database\n") ) ;
  return NT_STATUS_OK;
}

NTSTATUS pdb_pgsql_init(void) 
{
  return smb_register_passdb( PASSDB_INTERFACE_VERSION, "pgsql", pgsqlsam_init ) ;
}
-------------- next part --------------
diff -U5 -r samba-3.0.0/source/aclocal.m4 samba-3.0.0-new/source/aclocal.m4
--- samba-3.0.0/source/aclocal.m4	2003-08-29 09:42:42.000000000 +1200
+++ samba-3.0.0-new/source/aclocal.m4	2003-11-21 16:04:04.000000000 +1300
@@ -482,10 +482,55 @@
   fi
   AC_SUBST(MYSQL_CFLAGS)
   AC_SUBST(MYSQL_LIBS)
 ])
 
+# =========================================================================
+# AM_PATH_PGSQL : pgSQL library
+
+dnl AM_PATH_PGSQL([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for PGSQL, and define PGSQL_CFLAGS and PGSQL_LIBS
+dnl
+AC_DEFUN(AM_PATH_PGSQL,
+[dnl
+dnl Get the cflags and libraries from the pg_config script
+dnl
+AC_ARG_WITH(pgsql-prefix,[  --with-pgsql-prefix=PFX   Prefix where PostgreSQL is installed (optional)],
+            pgsql_prefix="$withval", pgsql_prefix="")
+AC_ARG_WITH(pgsql-exec-prefix,[  --with-pgsql-exec-prefix=PFX Exec prefix where PostgreSQL is installed (optional)],
+            pgsql_exec_prefix="$withval", pgsql_exec_prefix="")
+
+  if test x$pgsql_exec_prefix != x ; then
+     if test x${PGSQL_CONFIG+set} != xset ; then
+        PGSQL_CONFIG=$pgsql_exec_prefix/bin/pg_config
+     fi
+  fi
+  if test x$pgsql_prefix != x ; then
+     if test x${PGSQL_CONFIG+set} != xset ; then
+        PGSQL_CONFIG=$pgsql_prefix/bin/pg_config
+     fi
+  fi
+
+  AC_REQUIRE([AC_CANONICAL_TARGET])
+  AC_PATH_PROG(PGSQL_CONFIG, pg_config, no)
+  AC_MSG_CHECKING(for PGSQL)
+  no_pgsql=""
+  if test "$PGSQL_CONFIG" = "no" ; then
+    PGSQL_CFLAGS=""
+    PGSQL_LIBS=""
+    AC_MSG_RESULT(no)
+     ifelse([$2], , :, [$2])
+  else
+    PGSQL_CFLAGS=-I`$PGSQL_CONFIG --includedir`
+    PGSQL_LIBS="-lpq -L`$PGSQL_CONFIG --libdir`"
+    AC_MSG_RESULT(yes)
+    ifelse([$1], , :, [$1])
+  fi
+  AC_SUBST(PGSQL_CFLAGS)
+  AC_SUBST(PGSQL_LIBS)
+])
+
 dnl Removes -I/usr/include/? from given variable
 AC_DEFUN(CFLAGS_REMOVE_USR_INCLUDE,[
   ac_new_flags=""
   for i in [$]$1; do
     case [$]i in
diff -U5 -r samba-3.0.0/source/configure.in samba-3.0.0-new/source/configure.in
--- samba-3.0.0/source/configure.in	2003-09-25 05:16:13.000000000 +1200
+++ samba-3.0.0-new/source/configure.in	2003-11-21 15:24:58.000000000 +1300
@@ -2666,19 +2666,19 @@
   LIBS="$ac_save_LIBS"
 fi
 
 ########################################################
 # Compile experimental passdb backends?
-# (pdb_xml, pdb_mysql)
+# (pdb_xml, pdb_mysql, pdb_pgsql)
 AC_MSG_CHECKING(whether to build experimental passdb libraries)
 AC_ARG_WITH(expsam,
 [  --with-expsam=<list>    Include experimental passdb libraries (default=no)]
 [                          Valid choices include (comma separated list): ]
-[                              xml & mysql],
+[                              xml, pgsql & mysql],
 [ expsam_pdb_modules=`echo "$withval" | sed 's/,/ /g'`
   if test "z$expsam_pdb_modules" = "zyes"; then
-    expsam_pdb_modules="xml mysql"
+    expsam_pdb_modules="xml mysql pgsql"
   fi
   AC_MSG_RESULT($expsam_pdb_modules)
   for i in $expsam_pdb_modules
   do 
     case "$i" in
@@ -2690,10 +2690,15 @@
     mysql)
       ## pdb_mysql
       AM_PATH_MYSQL([default_shared_modules="$default_shared_modules pdb_mysql"],[])
       CFLAGS="$CFLAGS $MYSQL_CFLAGS"
       ;;
+    pgsql)
+      ## pdb_pgsql
+      AM_PATH_PGSQL([default_shared_modules="$default_shared_modules pdb_pgsql"],[])
+      CFLAGS="$CFLAGS $PGSQL_CFLAGS"
+      ;;
     no)
       ;;
     *)
       echo "Unknown module name \"$i\"!  Exiting..."
       exit 1
@@ -4085,10 +4090,12 @@
 
 SMB_MODULE(pdb_xml, passdb/pdb_xml.o, "bin/xml.$SHLIBEXT", PDB,
 		  [ PASSDB_LIBS="$PASSDB_LIBS $XML_LIBS" ] )
 SMB_MODULE(pdb_mysql, passdb/pdb_mysql.o, "bin/mysql.$SHLIBEXT", PDB, 
 		   [ PASSDB_LIBS="$PASSDB_LIBS $MYSQL_LIBS" ]	)
+SMB_MODULE(pdb_pgsql, passdb/pdb_pgsql.o, "bin/pgsql.$SHLIBEXT", PDB, 
+		   [ PASSDB_LIBS="$PASSDB_LIBS $PGSQL_LIBS" ]	)
 
 ## end of contributed pdb_modules
 ###########################################################################
 
 SMB_MODULE(pdb_ldap, passdb/pdb_ldap.o, "bin/ldapsam.$SHLIBEXT", PDB, 
diff -U5 -r samba-3.0.0/source/include/config.h.in samba-3.0.0-new/source/include/config.h.in
--- samba-3.0.0/source/include/config.h.in	2003-09-25 13:54:13.000000000 +1200
+++ samba-3.0.0-new/source/include/config.h.in	2003-11-21 15:27:50.000000000 +1300
@@ -1847,10 +1847,13 @@
 #undef pdb_ldap_init
 
 /* Whether to build pdb_mysql as shared module */
 #undef pdb_mysql_init
 
+/* Whether to build pdb_pgsql as shared module */
+#undef pdb_pgsql_init
+
 /* Whether to build pdb_smbpasswd as shared module */
 #undef pdb_smbpasswd_init
 
 /* Whether to build pdb_tdbsam as shared module */
 #undef pdb_tdbsam_init
diff -U5 -r samba-3.0.0/source/Makefile.in samba-3.0.0-new/source/Makefile.in
--- samba-3.0.0/source/Makefile.in	2003-09-25 05:16:13.000000000 +1200
+++ samba-3.0.0-new/source/Makefile.in	2003-11-21 15:42:38.000000000 +1300
@@ -285,10 +285,11 @@
 		passdb/machine_sid.o passdb/util_sam_sid.o passdb/pdb_compat.o \
 		passdb/privileges.o passdb/lookup_sid.o @PDB_STATIC@ 
 
 XML_OBJ = passdb/pdb_xml.o
 MYSQL_OBJ = passdb/pdb_mysql.o
+PGSQL_OBJ = passdb/pdb_pgsql.o
 DEVEL_HELP_WEIRD_OBJ = modules/weird.o
 DEVEL_HELP_CP850_OBJ = modules/CP850.o
 DEVEL_HELP_CP437_OBJ = modules/CP437.o
 
 GROUPDB_OBJ = groupdb/mapping.o
@@ -1050,10 +1051,15 @@
 bin/mysql. at SHLIBEXT@: $(MYSQL_OBJ:.o=.po)
 	@echo "Building plugin $@"
 	@$(SHLD) $(LDSHFLAGS) -o $@ $(MYSQL_OBJ:.o=.po) @MYSQL_LIBS@ \
 		@SONAMEFLAG@`basename $@`
 
+bin/pgsql. at SHLIBEXT@: $(PGSQL_OBJ:.o=.po)
+	@echo "Building plugin $@"
+	@$(SHLD) $(LDSHFLAGS) -o $@ $(PGSQL_OBJ:.o=.po) @PGSQL_LIBS@ \
+		@SONAMEFLAG@`basename $@`
+
 bin/ldapsam. at SHLIBEXT@: passdb/pdb_ldap.po
 	@echo "Building plugin $@"
 	@$(SHLD) $(LDSHFLAGS) $(LDAP_LIBS) -o $@ passdb/pdb_ldap.po \
 		@SONAMEFLAG@`basename $@`
 
-------------- next part --------------

CREATE TABLE samba (
	logon_time integer,
	logoff_time integer,
	kickoff_time integer,
	pass_last_set_time integer,
	pass_can_change_time integer,
	pass_must_change_time integer,
	username varchar(255),
	domain varchar(255),
	nt_username varchar(255),
	nt_fullname varchar(255),
	home_dir varchar(255),
	dir_drive varchar(4),
	logon_script varchar(255),
	profile_path varchar(255),
	acct_desc varchar(255),
	workstations varchar(255),
	unknown_str varchar(255),
	munged_dial varchar(255),
	uid serial,
	gid integer,
	user_sid varchar(255),
	group_sid varchar(255),
	lm_pw varchar(255),
	nt_pw varchar(255),
	acct_ctrl integer,
	unknown_3 integer,
	logon_divs integer,
	hours_len integer,
	unknown_5 integer,
	unknown_6 integer,
	PRIMARY KEY ( "uid" )
) ;



More information about the samba-technical mailing list