2 * PostgresSQL password backend for samba
3 * Copyright (C) Hamish Friedlander 2003
4 * Copyright (C) Jelmer Vernooij 2004
6 * This program is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 675
18 * Mass Ave, Cambridge, MA 02139, USA.
24 #define CONFIG_HOST_DEFAULT "localhost"
25 #define CONFIG_USER_DEFAULT "samba"
26 #define CONFIG_PASS_DEFAULT ""
27 #define CONFIG_PORT_DEFAULT "5432"
28 #define CONFIG_DB_DEFAULT "samba"
30 /* handles for doing db transactions */
31 typedef struct pdb_pgsql_data
{
36 const char *location
;
39 #define SET_DATA(data,methods) { \
41 DEBUG(0, ("invalid methods!\n")); \
42 return NT_STATUS_INVALID_PARAMETER; \
44 data = (struct pdb_pgsql_data *)methods->private_data; \
45 if(!data || !(data->handle)){ \
46 DEBUG(0, ("invalid handle!\n")); \
47 return NT_STATUS_INVALID_HANDLE; \
51 #define SET_DATA_QUIET(data,methods) { \
53 DEBUG(0, ("invalid methods!\n")); \
56 data = (struct pdb_pgsql_data *)methods->private_data; \
57 if(!data || !(data->handle)){ \
58 DEBUG(0, ("invalid handle!\n")); \
64 #define config_value( data, name, default_value ) \
65 lp_parm_const_string( GLOBAL_SECTION_SNUM, (data)->location, name, default_value )
67 static long PQgetlong( PGresult
*r
, long row
, long col
)
69 if ( PQgetisnull( r
, row
, col
) ) return 0 ;
71 return atol( PQgetvalue( r
, row
, col
) ) ;
74 static NTSTATUS
row_to_sam_account ( PGresult
*r
, long row
, SAM_ACCOUNT
*u
)
79 if ( row
>= PQntuples( r
) ) return NT_STATUS_INVALID_PARAMETER
;
81 pdb_set_logon_time ( u
, PQgetlong ( r
, row
, 0 ), PDB_SET
) ;
82 pdb_set_logoff_time ( u
, PQgetlong ( r
, row
, 1 ), PDB_SET
) ;
83 pdb_set_kickoff_time ( u
, PQgetlong ( r
, row
, 2 ), PDB_SET
) ;
84 pdb_set_pass_last_set_time ( u
, PQgetlong ( r
, row
, 3 ), PDB_SET
) ;
85 pdb_set_pass_can_change_time ( u
, PQgetlong ( r
, row
, 4 ), PDB_SET
) ;
86 pdb_set_pass_must_change_time( u
, PQgetlong ( r
, row
, 5 ), PDB_SET
) ;
87 pdb_set_username ( u
, PQgetvalue( r
, row
, 6 ), PDB_SET
) ;
88 pdb_set_domain ( u
, PQgetvalue( r
, row
, 7 ), PDB_SET
) ;
89 pdb_set_nt_username ( u
, PQgetvalue( r
, row
, 8 ), PDB_SET
) ;
90 pdb_set_fullname ( u
, PQgetvalue( r
, row
, 9 ), PDB_SET
) ;
91 pdb_set_homedir ( u
, PQgetvalue( r
, row
, 10 ), PDB_SET
) ;
92 pdb_set_dir_drive ( u
, PQgetvalue( r
, row
, 11 ), PDB_SET
) ;
93 pdb_set_logon_script ( u
, PQgetvalue( r
, row
, 12 ), PDB_SET
) ;
94 pdb_set_profile_path ( u
, PQgetvalue( r
, row
, 13 ), PDB_SET
) ;
95 pdb_set_acct_desc ( u
, PQgetvalue( r
, row
, 14 ), PDB_SET
) ;
96 pdb_set_workstations ( u
, PQgetvalue( r
, row
, 15 ), PDB_SET
) ;
97 pdb_set_unknown_str ( u
, PQgetvalue( r
, row
, 16 ), PDB_SET
) ;
98 pdb_set_munged_dial ( u
, PQgetvalue( r
, row
, 17 ), PDB_SET
) ;
100 pdb_set_acct_ctrl ( u
, PQgetlong ( r
, row
, 23 ), PDB_SET
) ;
101 pdb_set_unknown_3 ( u
, PQgetlong ( r
, row
, 24 ), PDB_SET
) ;
102 pdb_set_logon_divs ( u
, PQgetlong ( r
, row
, 25 ), PDB_SET
) ;
103 pdb_set_hours_len ( u
, PQgetlong ( r
, row
, 26 ), PDB_SET
) ;
104 pdb_set_logon_count ( u
, PQgetlong ( r
, row
, 27 ), PDB_SET
) ;
105 pdb_set_unknown_6 ( u
, PQgetlong ( r
, row
, 28 ), PDB_SET
) ;
107 if ( !PQgetisnull( r
, row
, 18 ) ) string_to_sid( &sid
, PQgetvalue( r
, row
, 18 ) ) ;
108 pdb_set_user_sid ( u
, &sid
, PDB_SET
) ;
109 if ( !PQgetisnull( r
, row
, 19 ) ) string_to_sid( &sid
, PQgetvalue( r
, row
, 19 ) ) ;
110 pdb_set_group_sid( u
, &sid
, PDB_SET
) ;
112 if ( pdb_gethexpwd( PQgetvalue( r
, row
, 20 ), temp
), PDB_SET
) pdb_set_lanman_passwd( u
, temp
, PDB_SET
) ;
113 if ( pdb_gethexpwd( PQgetvalue( r
, row
, 21 ), temp
), PDB_SET
) pdb_set_nt_passwd ( u
, temp
, PDB_SET
) ;
115 /* Only use plaintext password storage when lanman and nt are NOT used */
116 if ( PQgetisnull( r
, row
, 20 ) || PQgetisnull( r
, row
, 21 ) ) pdb_set_plaintext_passwd( u
, PQgetvalue( r
, row
, 22 ) ) ;
118 return NT_STATUS_OK
;
121 static NTSTATUS
pgsqlsam_setsampwent(struct pdb_methods
*methods
, BOOL update
)
123 struct pdb_pgsql_data
*data
;
127 SET_DATA( data
, methods
) ;
129 query
= sql_account_query_select(data
->location
, update
, SQL_SEARCH_NONE
, NULL
);
132 DEBUG( 5, ("Executing query %s\n", query
) ) ;
133 data
->pwent
= PQexec( data
->handle
, query
) ;
137 if ( data
->pwent
== NULL
)
139 DEBUG( 0, ("Error executing %s, %s\n", query
, PQerrorMessage( data
->handle
) ) ) ;
140 retval
= NT_STATUS_UNSUCCESSFUL
;
142 else if ( PQresultStatus( data
->pwent
) != PGRES_TUPLES_OK
)
144 DEBUG( 0, ("Error executing %s, %s\n", query
, PQresultErrorMessage( data
->pwent
) ) ) ;
145 retval
= NT_STATUS_UNSUCCESSFUL
;
149 DEBUG( 5, ("pgsqlsam_setsampwent succeeded(%llu results)!\n", PQntuples(data
->pwent
)) ) ;
150 retval
= NT_STATUS_OK
;
157 /***************************************************************
158 End enumeration of the passwd list.
159 ****************************************************************/
161 static void pgsqlsam_endsampwent(struct pdb_methods
*methods
)
163 struct pdb_pgsql_data
*data
;
165 SET_DATA_QUIET( data
, methods
) ;
167 if (data
->pwent
!= NULL
)
169 PQclear( data
->pwent
) ;
175 DEBUG( 5, ("pgsql_endsampwent called\n") ) ;
178 /*****************************************************************
179 Get one SAM_ACCOUNT from the list (next in line)
180 *****************************************************************/
182 static NTSTATUS
pgsqlsam_getsampwent( struct pdb_methods
*methods
, SAM_ACCOUNT
*user
)
184 struct pdb_pgsql_data
*data
;
187 SET_DATA( data
, methods
) ;
189 if ( data
->pwent
== NULL
)
191 DEBUG( 0, ("invalid pwent\n") ) ;
192 return NT_STATUS_INVALID_PARAMETER
;
195 retval
= row_to_sam_account( data
->pwent
, data
->currow
, user
) ;
201 static NTSTATUS
pgsqlsam_select_by_field ( struct pdb_methods
*methods
, SAM_ACCOUNT
*user
, enum sql_search_field field
, const char *sname
)
203 struct pdb_pgsql_data
*data
;
211 SET_DATA(data
, methods
);
215 DEBUG( 0, ("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n") ) ;
216 return NT_STATUS_INVALID_PARAMETER
;
219 DEBUG( 5, ("pgsqlsam_select_by_field: getting data where %d = %s(nonescaped)\n", field
, sname
) ) ;
222 esc
= malloc(strlen(sname
) * 2 + 1);
225 DEBUG(0, ("Can't allocate memory to store escaped name\n"));
226 return NT_STATUS_NO_MEMORY
;
229 //tmp_sname = smb_xstrdup(sname);
230 PQescapeString( esc
, sname
, strlen(sname
) ) ;
232 query
= sql_account_query_select(data
->location
, True
, field
, esc
);
235 DEBUG( 5, ("Executing query %s\n", query
) ) ;
236 result
= PQexec( data
->handle
, query
) ;
239 if ( result
== NULL
)
241 DEBUG( 0, ("Error executing %s, %s\n", query
, PQerrorMessage( data
->handle
) ) ) ;
242 retval
= NT_STATUS_UNSUCCESSFUL
;
244 else if ( PQresultStatus( result
) != PGRES_TUPLES_OK
)
246 DEBUG( 0, ("Error executing %s, %s\n", query
, PQresultErrorMessage( result
) ) ) ;
247 retval
= NT_STATUS_UNSUCCESSFUL
;
251 retval
= row_to_sam_account( result
, 0, user
) ;
262 /******************************************************************
263 Lookup a name in the SAM database
264 ******************************************************************/
266 static NTSTATUS
pgsqlsam_getsampwnam ( struct pdb_methods
*methods
, SAM_ACCOUNT
*user
, const char *sname
)
268 struct pdb_pgsql_data
*data
;
270 SET_DATA(data
, methods
);
274 DEBUG( 0, ("invalid name specified") ) ;
275 return NT_STATUS_INVALID_PARAMETER
;
278 return pgsqlsam_select_by_field( methods
, user
, SQL_SEARCH_USER_NAME
, sname
) ;
282 /***************************************************************************
284 **************************************************************************/
286 static NTSTATUS
pgsqlsam_getsampwsid ( struct pdb_methods
*methods
, SAM_ACCOUNT
*user
, const DOM_SID
*sid
)
288 struct pdb_pgsql_data
*data
;
291 SET_DATA( data
, methods
) ;
293 sid_to_string( sid_str
, sid
) ;
295 return pgsqlsam_select_by_field( methods
, user
, SQL_SEARCH_USER_SID
, sid_str
) ;
298 /***************************************************************************
300 ****************************************************************************/
302 static NTSTATUS
pgsqlsam_delete_sam_account( struct pdb_methods
*methods
, SAM_ACCOUNT
*sam_pass
)
304 struct pdb_pgsql_data
*data
;
306 const char *sname
= pdb_get_username( sam_pass
) ;
313 SET_DATA(data
, methods
);
317 DEBUG( 0, ("invalid name specified\n") ) ;
318 return NT_STATUS_INVALID_PARAMETER
;
322 esc
= malloc(strlen(sname
) * 2 + 1);
325 DEBUG(0, ("Can't allocate memory to store escaped name\n"));
326 return NT_STATUS_NO_MEMORY
;
329 PQescapeString( esc
, sname
, strlen(sname
) ) ;
331 query
= sql_account_query_delete(data
->location
, esc
);
334 result
= PQexec( data
->handle
, query
) ;
336 if ( result
== NULL
)
338 DEBUG( 0, ("Error executing %s, %s\n", query
, PQerrorMessage( data
->handle
) ) ) ;
339 retval
= NT_STATUS_UNSUCCESSFUL
;
341 else if ( PQresultStatus( result
) != PGRES_COMMAND_OK
)
343 DEBUG( 0, ("Error executing %s, %s\n", query
, PQresultErrorMessage( result
) ) ) ;
344 retval
= NT_STATUS_UNSUCCESSFUL
;
348 DEBUG( 5, ("User '%s' deleted\n", sname
) ) ;
349 retval
= NT_STATUS_OK
;
358 static NTSTATUS
pgsqlsam_replace_sam_account( struct pdb_methods
*methods
, const SAM_ACCOUNT
*newpwd
, char isupdate
)
360 struct pdb_pgsql_data
*data
;
366 DEBUG( 0, ("invalid methods!\n") ) ;
367 return NT_STATUS_INVALID_PARAMETER
;
370 data
= (struct pdb_pgsql_data
*) methods
->private_data
;
372 if ( data
== NULL
|| data
->handle
== NULL
)
374 DEBUG( 0, ("invalid handle!\n") ) ;
375 return NT_STATUS_INVALID_HANDLE
;
378 query
= sql_account_query_update(data
->location
, newpwd
, isupdate
);
380 result
= PQexec( data
->handle
, query
) ;
383 /* Execute the query */
384 if ( result
== NULL
)
386 DEBUG( 0, ("Error executing %s, %s\n", query
, PQerrorMessage( data
->handle
) ) ) ;
387 return NT_STATUS_INVALID_PARAMETER
;
389 else if ( PQresultStatus( result
) != PGRES_COMMAND_OK
)
391 DEBUG( 0, ("Error executing %s, %s\n", query
, PQresultErrorMessage( result
) ) ) ;
392 return NT_STATUS_INVALID_PARAMETER
;
399 static NTSTATUS
pgsqlsam_add_sam_account ( struct pdb_methods
*methods
, SAM_ACCOUNT
*newpwd
)
401 return pgsqlsam_replace_sam_account( methods
, newpwd
, 0 ) ;
404 static NTSTATUS
pgsqlsam_update_sam_account ( struct pdb_methods
*methods
, SAM_ACCOUNT
*newpwd
)
406 return pgsqlsam_replace_sam_account( methods
, newpwd
, 1 ) ;
409 static NTSTATUS
pgsqlsam_init ( struct pdb_context
*pdb_context
, struct pdb_methods
**pdb_method
, const char *location
)
412 struct pdb_pgsql_data
*data
;
416 DEBUG( 0, ("invalid pdb_methods specified\n") ) ;
417 return NT_STATUS_UNSUCCESSFUL
;
421 (nt_status
= make_pdb_methods(pdb_context
->mem_ctx
, pdb_method
))) {
425 (*pdb_method
)->name
= "pgsqlsam" ;
427 (*pdb_method
)->setsampwent
= pgsqlsam_setsampwent
;
428 (*pdb_method
)->endsampwent
= pgsqlsam_endsampwent
;
429 (*pdb_method
)->getsampwent
= pgsqlsam_getsampwent
;
430 (*pdb_method
)->getsampwnam
= pgsqlsam_getsampwnam
;
431 (*pdb_method
)->getsampwsid
= pgsqlsam_getsampwsid
;
432 (*pdb_method
)->add_sam_account
= pgsqlsam_add_sam_account
;
433 (*pdb_method
)->update_sam_account
= pgsqlsam_update_sam_account
;
434 (*pdb_method
)->delete_sam_account
= pgsqlsam_delete_sam_account
;
436 data
= talloc( pdb_context
->mem_ctx
, sizeof( struct pdb_pgsql_data
) ) ;
437 (*pdb_method
)->private_data
= data
;
438 data
->handle
= NULL
;
443 DEBUG( 0, ("No identifier specified. Check the Samba HOWTO Collection for details\n") ) ;
444 return NT_STATUS_INVALID_PARAMETER
;
447 data
->location
= smb_xstrdup( location
) ;
449 if(!sql_account_config_valid(data
->location
)) {
450 return NT_STATUS_INVALID_PARAMETER
;
457 "Connecting to database server, host: %s, user: %s, password: XXXXXX, database: %s, port: %s\n",
458 config_value( data
, "pgsql host" , CONFIG_HOST_DEFAULT
),
459 config_value( data
, "pgsql user" , CONFIG_USER_DEFAULT
),
460 config_value( data
, "pgsql database", CONFIG_DB_DEFAULT
),
461 config_value( data
, "pgsql port" , CONFIG_PORT_DEFAULT
)
465 /* Do the pgsql initialization */
466 data
->handle
= PQsetdbLogin(
467 config_value( data
, "pgsql host" , CONFIG_HOST_DEFAULT
),
468 config_value( data
, "pgsql port" , CONFIG_PORT_DEFAULT
),
471 config_value( data
, "pgsql database", CONFIG_DB_DEFAULT
),
472 config_value( data
, "pgsql user" , CONFIG_USER_DEFAULT
),
473 config_value( data
, "pgsql password", CONFIG_PASS_DEFAULT
)
476 if ( PQstatus( data
->handle
) != CONNECTION_OK
)
478 DEBUG( 0, ("Failed to connect to pgsql database: error: %s\n", PQerrorMessage( data
->handle
)) ) ;
479 return NT_STATUS_UNSUCCESSFUL
;
482 DEBUG( 5, ("Connected to pgsql database\n") ) ;
486 NTSTATUS
pdb_pgsql_init(void)
488 return smb_register_passdb( PASSDB_INTERFACE_VERSION
, "pgsql", pgsqlsam_init
) ;