r8839: adding patches from Marcin. Have to still work on
[Samba.git] / source / passdb / pdb_pgsql.c
blob4fb674d20427c79dba56b23ab431f33f49ccdfea
1 /*
2 * PostgresSQL password backend for samba
3 * Copyright (C) Hamish Friedlander 2003
4 * Copyright (C) Jelmer Vernooij 2004
5 *
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)
9 * any later version.
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
14 * more details.
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.
21 #include "includes.h"
22 #include <libpq-fe.h>
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 {
32 PGconn *handle ;
33 PGresult *pwent ;
34 long currow ;
36 const char *location ;
37 } pdb_pgsql_data ;
39 #define SET_DATA(data,methods) { \
40 if(!methods){ \
41 DEBUG(0, ("invalid methods!\n")); \
42 return NT_STATUS_INVALID_PARAMETER; \
43 } \
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; \
48 } \
51 #define SET_DATA_QUIET(data,methods) { \
52 if(!methods){ \
53 DEBUG(0, ("invalid methods!\n")); \
54 return ; \
55 } \
56 data = (struct pdb_pgsql_data *)methods->private_data; \
57 if(!data || !(data->handle)){ \
58 DEBUG(0, ("invalid handle!\n")); \
59 return ; \
60 } \
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 )
76 pstring temp ;
77 DOM_SID sid ;
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_logon_divs ( u, PQgetlong ( r, row, 24 ), PDB_SET ) ;
102 pdb_set_hours_len ( u, PQgetlong ( r, row, 25 ), PDB_SET ) ;
103 pdb_set_bad_password_count ( 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 ) ) {
108 string_to_sid( &sid, PQgetvalue( r, row, 18 ) ) ;
109 pdb_set_user_sid ( u, &sid, PDB_SET ) ;
112 if ( !PQgetisnull( r, row, 19 ) ) {
113 string_to_sid( &sid, PQgetvalue( r, row, 19 ) ) ;
114 pdb_set_group_sid( u, &sid, PDB_SET ) ;
117 if ( pdb_gethexpwd( PQgetvalue( r, row, 20 ), temp ), PDB_SET ) pdb_set_lanman_passwd( u, temp, PDB_SET ) ;
118 if ( pdb_gethexpwd( PQgetvalue( r, row, 21 ), temp ), PDB_SET ) pdb_set_nt_passwd ( u, temp, PDB_SET ) ;
120 /* Only use plaintext password storage when lanman and nt are NOT used */
121 if ( PQgetisnull( r, row, 20 ) || PQgetisnull( r, row, 21 ) ) pdb_set_plaintext_passwd( u, PQgetvalue( r, row, 22 ) ) ;
123 return NT_STATUS_OK ;
126 static NTSTATUS pgsqlsam_setsampwent(struct pdb_methods *methods, BOOL update, uint16 acb_mask)
128 struct pdb_pgsql_data *data ;
129 char *query ;
130 NTSTATUS retval ;
132 SET_DATA( data, methods ) ;
134 query = sql_account_query_select(NULL, data->location, update, SQL_SEARCH_NONE, NULL);
136 /* Do it */
137 DEBUG( 5, ("Executing query %s\n", query) ) ;
138 data->pwent = PQexec( data->handle, query ) ;
139 data->currow = 0 ;
141 /* Result? */
142 if ( data->pwent == NULL )
144 DEBUG( 0, ("Error executing %s, %s\n", query, PQerrorMessage( data->handle ) ) ) ;
145 retval = NT_STATUS_UNSUCCESSFUL ;
147 else if ( PQresultStatus( data->pwent ) != PGRES_TUPLES_OK )
149 DEBUG( 0, ("Error executing %s, %s\n", query, PQresultErrorMessage( data->pwent ) ) ) ;
150 retval = NT_STATUS_UNSUCCESSFUL ;
152 else
154 DEBUG( 5, ("pgsqlsam_setsampwent succeeded(%d results)!\n", PQntuples(data->pwent)) ) ;
155 retval = NT_STATUS_OK ;
158 talloc_free(query);
159 return retval ;
162 /***************************************************************
163 End enumeration of the passwd list.
164 ****************************************************************/
166 static void pgsqlsam_endsampwent(struct pdb_methods *methods)
168 struct pdb_pgsql_data *data ;
170 SET_DATA_QUIET( data, methods ) ;
172 if (data->pwent != NULL)
174 PQclear( data->pwent ) ;
177 data->pwent = NULL ;
178 data->currow = 0 ;
180 DEBUG( 5, ("pgsql_endsampwent called\n") ) ;
183 /*****************************************************************
184 Get one SAM_ACCOUNT from the list (next in line)
185 *****************************************************************/
187 static NTSTATUS pgsqlsam_getsampwent( struct pdb_methods *methods, SAM_ACCOUNT *user )
189 struct pdb_pgsql_data *data;
190 NTSTATUS retval ;
192 SET_DATA( data, methods ) ;
194 if ( data->pwent == NULL )
196 DEBUG( 0, ("invalid pwent\n") ) ;
197 return NT_STATUS_INVALID_PARAMETER ;
200 retval = row_to_sam_account( data->pwent, data->currow, user ) ;
201 data->currow++ ;
203 return retval ;
206 static NTSTATUS pgsqlsam_select_by_field ( struct pdb_methods *methods, SAM_ACCOUNT *user, enum sql_search_field field, const char *sname )
208 struct pdb_pgsql_data *data ;
210 char *esc ;
211 char *query ;
213 PGresult *result ;
214 NTSTATUS retval ;
216 SET_DATA(data, methods);
218 if ( user == NULL )
220 DEBUG( 0, ("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n") ) ;
221 return NT_STATUS_INVALID_PARAMETER;
224 DEBUG( 5, ("pgsqlsam_select_by_field: getting data where %d = %s(nonescaped)\n", field, sname) ) ;
226 /* Escape sname */
227 esc = talloc_array(NULL, char, strlen(sname) * 2 + 1);
228 if ( !esc )
230 DEBUG(0, ("Can't allocate memory to store escaped name\n"));
231 return NT_STATUS_NO_MEMORY;
234 //tmp_sname = smb_xstrdup(sname);
235 PQescapeString( esc, sname, strlen(sname) ) ;
237 query = sql_account_query_select(NULL, data->location, True, field, esc);
239 /* Do it */
240 DEBUG( 5, ("Executing query %s\n", query) ) ;
241 result = PQexec( data->handle, query ) ;
243 /* Result? */
244 if ( result == NULL )
246 DEBUG( 0, ("Error executing %s, %s\n", query, PQerrorMessage( data->handle ) ) ) ;
247 retval = NT_STATUS_UNSUCCESSFUL ;
249 else if ( PQresultStatus( result ) != PGRES_TUPLES_OK )
251 DEBUG( 0, ("Error executing %s, %s\n", query, PQresultErrorMessage( result ) ) ) ;
252 retval = NT_STATUS_UNSUCCESSFUL ;
254 else
256 retval = row_to_sam_account( result, 0, user ) ;
259 talloc_free( esc ) ;
260 talloc_free( query ) ;
262 PQclear( result ) ;
264 return retval ;
267 /******************************************************************
268 Lookup a name in the SAM database
269 ******************************************************************/
271 static NTSTATUS pgsqlsam_getsampwnam ( struct pdb_methods *methods, SAM_ACCOUNT *user, const char *sname )
273 struct pdb_pgsql_data *data;
275 SET_DATA(data, methods);
277 if ( !sname )
279 DEBUG( 0, ("invalid name specified") ) ;
280 return NT_STATUS_INVALID_PARAMETER;
283 return pgsqlsam_select_by_field( methods, user, SQL_SEARCH_USER_NAME, sname ) ;
287 /***************************************************************************
288 Search by sid
289 **************************************************************************/
291 static NTSTATUS pgsqlsam_getsampwsid ( struct pdb_methods *methods, SAM_ACCOUNT *user, const DOM_SID *sid )
293 struct pdb_pgsql_data *data;
294 fstring sid_str;
296 SET_DATA( data, methods ) ;
298 sid_to_string( sid_str, sid ) ;
300 return pgsqlsam_select_by_field( methods, user, SQL_SEARCH_USER_SID, sid_str ) ;
303 /***************************************************************************
304 Delete a SAM_ACCOUNT
305 ****************************************************************************/
307 static NTSTATUS pgsqlsam_delete_sam_account( struct pdb_methods *methods, SAM_ACCOUNT *sam_pass )
309 struct pdb_pgsql_data *data ;
311 const char *sname = pdb_get_username( sam_pass ) ;
312 char *esc ;
313 char *query ;
315 PGresult *result ;
316 NTSTATUS retval ;
318 SET_DATA(data, methods);
320 if ( !sname )
322 DEBUG( 0, ("invalid name specified\n") ) ;
323 return NT_STATUS_INVALID_PARAMETER ;
326 /* Escape sname */
327 esc = talloc_array(NULL, char, strlen(sname) * 2 + 1);
328 if ( !esc )
330 DEBUG(0, ("Can't allocate memory to store escaped name\n"));
331 return NT_STATUS_NO_MEMORY;
334 PQescapeString( esc, sname, strlen(sname) ) ;
336 query = sql_account_query_delete(NULL, data->location, esc);
338 /* Do it */
339 result = PQexec( data->handle, query ) ;
341 if ( result == NULL )
343 DEBUG( 0, ("Error executing %s, %s\n", query, PQerrorMessage( data->handle ) ) ) ;
344 retval = NT_STATUS_UNSUCCESSFUL ;
346 else if ( PQresultStatus( result ) != PGRES_COMMAND_OK )
348 DEBUG( 0, ("Error executing %s, %s\n", query, PQresultErrorMessage( result ) ) ) ;
349 retval = NT_STATUS_UNSUCCESSFUL ;
351 else
353 DEBUG( 5, ("User '%s' deleted\n", sname) ) ;
354 retval = NT_STATUS_OK ;
357 talloc_free( esc ) ;
358 talloc_free( query ) ;
360 return retval ;
363 static NTSTATUS pgsqlsam_replace_sam_account( struct pdb_methods *methods, const SAM_ACCOUNT *newpwd, char isupdate )
365 struct pdb_pgsql_data *data ;
366 char *query;
367 PGresult *result ;
369 if ( !methods )
371 DEBUG( 0, ("invalid methods!\n") ) ;
372 return NT_STATUS_INVALID_PARAMETER ;
375 data = (struct pdb_pgsql_data *) methods->private_data ;
377 if ( data == NULL || data->handle == NULL )
379 DEBUG( 0, ("invalid handle!\n") ) ;
380 return NT_STATUS_INVALID_HANDLE ;
383 query = sql_account_query_update(NULL, data->location, newpwd, isupdate);
385 result = PQexec( data->handle, query ) ;
388 /* Execute the query */
389 if ( result == NULL )
391 DEBUG( 0, ("Error executing %s, %s\n", query, PQerrorMessage( data->handle ) ) ) ;
392 return NT_STATUS_INVALID_PARAMETER;
394 else if ( PQresultStatus( result ) != PGRES_COMMAND_OK )
396 DEBUG( 0, ("Error executing %s, %s\n", query, PQresultErrorMessage( result ) ) ) ;
397 return NT_STATUS_INVALID_PARAMETER;
399 talloc_free(query);
401 return NT_STATUS_OK;
404 static NTSTATUS pgsqlsam_add_sam_account ( struct pdb_methods *methods, SAM_ACCOUNT *newpwd )
406 return pgsqlsam_replace_sam_account( methods, newpwd, 0 ) ;
409 static NTSTATUS pgsqlsam_update_sam_account ( struct pdb_methods *methods, SAM_ACCOUNT *newpwd )
411 return pgsqlsam_replace_sam_account( methods, newpwd, 1 ) ;
414 static NTSTATUS pgsqlsam_init ( struct pdb_context *pdb_context, struct pdb_methods **pdb_method, const char *location )
416 NTSTATUS nt_status ;
417 struct pdb_pgsql_data *data ;
419 if ( !pdb_context )
421 DEBUG( 0, ("invalid pdb_methods specified\n") ) ;
422 return NT_STATUS_UNSUCCESSFUL;
425 if (!NT_STATUS_IS_OK
426 (nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
427 return nt_status;
430 (*pdb_method)->name = "pgsqlsam" ;
432 (*pdb_method)->setsampwent = pgsqlsam_setsampwent ;
433 (*pdb_method)->endsampwent = pgsqlsam_endsampwent ;
434 (*pdb_method)->getsampwent = pgsqlsam_getsampwent ;
435 (*pdb_method)->getsampwnam = pgsqlsam_getsampwnam ;
436 (*pdb_method)->getsampwsid = pgsqlsam_getsampwsid ;
437 (*pdb_method)->add_sam_account = pgsqlsam_add_sam_account ;
438 (*pdb_method)->update_sam_account = pgsqlsam_update_sam_account ;
439 (*pdb_method)->delete_sam_account = pgsqlsam_delete_sam_account ;
441 data = talloc( pdb_context->mem_ctx, struct pdb_pgsql_data ) ;
442 (*pdb_method)->private_data = data ;
443 data->handle = NULL ;
444 data->pwent = NULL ;
446 if ( !location )
448 DEBUG( 0, ("No identifier specified. Check the Samba HOWTO Collection for details\n") ) ;
449 return NT_STATUS_INVALID_PARAMETER;
452 data->location = smb_xstrdup( location ) ;
454 if(!sql_account_config_valid(data->location)) {
455 return NT_STATUS_INVALID_PARAMETER;
458 DEBUG
462 "Connecting to database server, host: %s, user: %s, password: XXXXXX, database: %s, port: %s\n",
463 config_value( data, "pgsql host" , CONFIG_HOST_DEFAULT ),
464 config_value( data, "pgsql user" , CONFIG_USER_DEFAULT ),
465 config_value( data, "pgsql database", CONFIG_DB_DEFAULT ),
466 config_value( data, "pgsql port" , CONFIG_PORT_DEFAULT )
470 /* Do the pgsql initialization */
471 data->handle = PQsetdbLogin(
472 config_value( data, "pgsql host" , CONFIG_HOST_DEFAULT ),
473 config_value( data, "pgsql port" , CONFIG_PORT_DEFAULT ),
474 NULL,
475 NULL,
476 config_value( data, "pgsql database", CONFIG_DB_DEFAULT ),
477 config_value( data, "pgsql user" , CONFIG_USER_DEFAULT ),
478 config_value( data, "pgsql password", CONFIG_PASS_DEFAULT )
481 if ( PQstatus( data->handle ) != CONNECTION_OK )
483 DEBUG( 0, ("Failed to connect to pgsql database: error: %s\n", PQerrorMessage( data->handle )) ) ;
484 return NT_STATUS_UNSUCCESSFUL;
487 DEBUG( 5, ("Connected to pgsql database\n") ) ;
488 return NT_STATUS_OK;
491 NTSTATUS pdb_pgsql_init(void)
493 return smb_register_passdb( PASSDB_INTERFACE_VERSION, "pgsql", pgsqlsam_init ) ;