r10606: pdb_*sql patches from
[Samba.git] / source / passdb / pdb_pgsql.c
blob632903c1ac38d33aa4bb862b8bb9974121277e21
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 *master_handle ;
33 PGconn *handle ;
35 PGresult *pwent ;
36 long currow ;
37 const char *db ;
38 const char *host ;
39 const char *port ;
40 const char *user ;
41 const char *pass ;
43 const char *location ;
44 } pdb_pgsql_data ;
46 struct pdb_context *the_pdb_context;
48 #define SET_DATA(data,methods) { \
49 if(!methods){ \
50 DEBUG(0, ("invalid methods!\n")); \
51 return NT_STATUS_INVALID_PARAMETER; \
52 } \
53 data = (struct pdb_pgsql_data *)methods->private_data; \
57 #define SET_DATA_QUIET(data,methods) { \
58 if(!methods){ \
59 DEBUG(0, ("invalid methods!\n")); \
60 return ; \
61 } \
62 data = (struct pdb_pgsql_data *)methods->private_data; \
66 #define config_value( data, name, default_value ) \
67 lp_parm_const_string( GLOBAL_SECTION_SNUM, (data)->location, name, default_value )
69 static PGconn *pgsqlsam_connect( struct pdb_pgsql_data *data )
71 PGconn *handle;
73 DEBUG
75 1,
77 "Connecting to database server, host: %s, user: %s, password: XXXXXX, database: %s, port: %s\n",
78 data->host, data->user, data->db, data->port
80 ) ;
82 /* Do the pgsql initialization */
83 handle = PQsetdbLogin(
84 data->host,
85 data->port,
86 NULL,
87 NULL,
88 data->db,
89 data->user,
90 data->pass
91 ) ;
93 if ( handle != NULL && PQstatus( handle ) != CONNECTION_OK )
95 DEBUG( 0, ("Failed to connect to pgsql database: error: %s\n",
96 (handle != NULL ? PQerrorMessage( handle ) : "")) ) ;
97 return NULL;
100 DEBUG( 5, ("Connected to pgsql database\n") ) ;
101 return handle;
104 /* The assumption here is that the master process will get connection 0,
105 * and all the renaining ones just one connection for their etire life span.
107 static PGconn *choose_connection( struct pdb_pgsql_data *data )
109 if ( data->master_handle == NULL )
111 data->master_handle = pgsqlsam_connect( data );
112 return data->master_handle ;
115 /* Master connection != NULL, so we are just another process. */
117 /* If we didn't connect yet, do it now. */
118 if ( data->handle == NULL )
120 data->handle = pgsqlsam_connect( data );
123 return data->handle ;
126 static long PQgetlong( PGresult *r, long row, long col )
128 if ( PQgetisnull( r, row, col ) ) return 0 ;
130 return atol( PQgetvalue( r, row, col ) ) ;
133 static NTSTATUS row_to_sam_account ( PGresult *r, long row, SAM_ACCOUNT *u )
135 pstring temp ;
136 DOM_SID sid ;
137 unsigned char *hours ;
138 size_t hours_len = 0 ;
140 if ( row >= PQntuples( r ) ) return NT_STATUS_INVALID_PARAMETER ;
142 pdb_set_logon_time ( u, PQgetlong ( r, row, 0 ), PDB_SET ) ;
143 pdb_set_logoff_time ( u, PQgetlong ( r, row, 1 ), PDB_SET ) ;
144 pdb_set_kickoff_time ( u, PQgetlong ( r, row, 2 ), PDB_SET ) ;
145 pdb_set_pass_last_set_time ( u, PQgetlong ( r, row, 3 ), PDB_SET ) ;
146 pdb_set_pass_can_change_time ( u, PQgetlong ( r, row, 4 ), PDB_SET ) ;
147 pdb_set_pass_must_change_time( u, PQgetlong ( r, row, 5 ), PDB_SET ) ;
148 pdb_set_username ( u, PQgetvalue( r, row, 6 ), PDB_SET ) ;
149 pdb_set_domain ( u, PQgetvalue( r, row, 7 ), PDB_SET ) ;
150 pdb_set_nt_username ( u, PQgetvalue( r, row, 8 ), PDB_SET ) ;
151 pdb_set_fullname ( u, PQgetvalue( r, row, 9 ), PDB_SET ) ;
152 pdb_set_homedir ( u, PQgetvalue( r, row, 10 ), PDB_SET ) ;
153 pdb_set_dir_drive ( u, PQgetvalue( r, row, 11 ), PDB_SET ) ;
154 pdb_set_logon_script ( u, PQgetvalue( r, row, 12 ), PDB_SET ) ;
155 pdb_set_profile_path ( u, PQgetvalue( r, row, 13 ), PDB_SET ) ;
156 pdb_set_acct_desc ( u, PQgetvalue( r, row, 14 ), PDB_SET ) ;
157 pdb_set_workstations ( u, PQgetvalue( r, row, 15 ), PDB_SET ) ;
158 pdb_set_unknown_str ( u, PQgetvalue( r, row, 16 ), PDB_SET ) ;
159 pdb_set_munged_dial ( u, PQgetvalue( r, row, 17 ), PDB_SET ) ;
161 pdb_set_acct_ctrl ( u, PQgetlong ( r, row, 23 ), PDB_SET ) ;
162 pdb_set_logon_divs ( u, PQgetlong ( r, row, 24 ), PDB_SET ) ;
163 pdb_set_hours_len ( u, PQgetlong ( r, row, 25 ), PDB_SET ) ;
164 pdb_set_bad_password_count ( u, PQgetlong ( r, row, 26 ), PDB_SET ) ;
165 pdb_set_logon_count ( u, PQgetlong ( r, row, 27 ), PDB_SET ) ;
166 pdb_set_unknown_6 ( u, PQgetlong ( r, row, 28 ), PDB_SET ) ;
167 hours = PQgetvalue ( r, row, 29 );
168 if ( hours != NULL ) {
169 hours = PQunescapeBytea ( hours, &hours_len ) ;
170 if ( hours_len > 0 )
171 pdb_set_hours ( u, hours, PDB_SET ) ;
172 free ( hours );
175 if ( !PQgetisnull( r, row, 18 ) ) {
176 string_to_sid( &sid, PQgetvalue( r, row, 18 ) ) ;
177 pdb_set_user_sid ( u, &sid, PDB_SET ) ;
180 if ( !PQgetisnull( r, row, 19 ) ) {
181 string_to_sid( &sid, PQgetvalue( r, row, 19 ) ) ;
182 pdb_set_group_sid( u, &sid, PDB_SET ) ;
185 if ( pdb_gethexpwd( PQgetvalue( r, row, 20 ), temp ), PDB_SET ) pdb_set_lanman_passwd( u, temp, PDB_SET ) ;
186 if ( pdb_gethexpwd( PQgetvalue( r, row, 21 ), temp ), PDB_SET ) pdb_set_nt_passwd ( u, temp, PDB_SET ) ;
188 /* Only use plaintext password storage when lanman and nt are NOT used */
189 if ( PQgetisnull( r, row, 20 ) || PQgetisnull( r, row, 21 ) ) pdb_set_plaintext_passwd( u, PQgetvalue( r, row, 22 ) ) ;
191 return NT_STATUS_OK ;
194 static NTSTATUS pgsqlsam_setsampwent(struct pdb_methods *methods, BOOL update, uint16 acb_mask)
196 struct pdb_pgsql_data *data ;
197 PGconn *handle ;
198 char *query ;
199 NTSTATUS retval ;
201 SET_DATA( data, methods ) ;
203 /* Connect to the DB. */
204 handle = choose_connection( data );
205 if ( handle == NULL )
206 return NT_STATUS_UNSUCCESSFUL ;
207 DEBUG( 5, ("CONNECTING pgsqlsam_setsampwent\n") ) ;
209 query = sql_account_query_select(NULL, data->location, update, SQL_SEARCH_NONE, NULL);
211 /* Do it */
212 DEBUG( 5, ("Executing query %s\n", query) ) ;
213 data->pwent = PQexec( handle, query ) ;
214 data->currow = 0 ;
216 /* Result? */
217 if ( data->pwent == NULL )
219 DEBUG( 0, ("Error executing %s, %s\n", query, PQerrorMessage( handle ) ) ) ;
220 retval = NT_STATUS_UNSUCCESSFUL ;
222 else if ( PQresultStatus( data->pwent ) != PGRES_TUPLES_OK )
224 DEBUG( 0, ("Error executing %s, %s\n", query, PQresultErrorMessage( data->pwent ) ) ) ;
225 retval = NT_STATUS_UNSUCCESSFUL ;
227 else
229 DEBUG( 5, ("pgsqlsam_setsampwent succeeded(%d results)!\n", PQntuples(data->pwent)) ) ;
230 retval = NT_STATUS_OK ;
233 talloc_free(query);
234 return retval ;
237 /***************************************************************
238 End enumeration of the passwd list.
239 ****************************************************************/
241 static void pgsqlsam_endsampwent(struct pdb_methods *methods)
243 struct pdb_pgsql_data *data ;
245 SET_DATA_QUIET( data, methods ) ;
247 if (data->pwent != NULL)
249 PQclear( data->pwent ) ;
252 data->pwent = NULL ;
253 data->currow = 0 ;
255 DEBUG( 5, ("pgsql_endsampwent called\n") ) ;
258 /*****************************************************************
259 Get one SAM_ACCOUNT from the list (next in line)
260 *****************************************************************/
262 static NTSTATUS pgsqlsam_getsampwent( struct pdb_methods *methods, SAM_ACCOUNT *user )
264 struct pdb_pgsql_data *data;
265 NTSTATUS retval ;
267 SET_DATA( data, methods ) ;
269 if ( data->pwent == NULL )
271 DEBUG( 0, ("invalid pwent\n") ) ;
272 return NT_STATUS_INVALID_PARAMETER ;
275 retval = row_to_sam_account( data->pwent, data->currow, user ) ;
276 data->currow++ ;
278 return retval ;
281 static NTSTATUS pgsqlsam_select_by_field ( struct pdb_methods *methods, SAM_ACCOUNT *user, enum sql_search_field field, const char *sname )
283 struct pdb_pgsql_data *data ;
284 PGconn *handle ;
286 char *esc ;
287 char *query ;
289 PGresult *result ;
290 NTSTATUS retval ;
292 SET_DATA(data, methods);
294 if ( user == NULL )
296 DEBUG( 0, ("pdb_getsampwnam: SAM_ACCOUNT is NULL.\n") ) ;
297 return NT_STATUS_INVALID_PARAMETER;
300 DEBUG( 5, ("pgsqlsam_select_by_field: getting data where %d = %s(nonescaped)\n", field, sname) ) ;
302 /* Escape sname */
303 esc = talloc_array(NULL, char, strlen(sname) * 2 + 1);
304 if ( !esc )
306 DEBUG(0, ("Can't allocate memory to store escaped name\n"));
307 return NT_STATUS_NO_MEMORY;
310 //tmp_sname = smb_xstrdup(sname);
311 PQescapeString( esc, sname, strlen(sname) ) ;
313 /* Connect to the DB. */
314 handle = choose_connection( data );
315 if ( handle == NULL )
316 return NT_STATUS_UNSUCCESSFUL ;
318 query = sql_account_query_select(NULL, data->location, True, field, esc);
320 /* Do it */
321 DEBUG( 5, ("Executing query %s\n", query) ) ;
322 result = PQexec( handle, query ) ;
324 /* Result? */
325 if ( result == NULL )
327 DEBUG( 0, ("Error executing %s, %s\n", query, PQerrorMessage( handle ) ) ) ;
328 retval = NT_STATUS_UNSUCCESSFUL ;
330 else if ( PQresultStatus( result ) != PGRES_TUPLES_OK )
332 DEBUG( 0, ("Error executing %s, %s\n", query, PQresultErrorMessage( result ) ) ) ;
333 retval = NT_STATUS_UNSUCCESSFUL ;
335 else
337 retval = row_to_sam_account( result, 0, user ) ;
340 talloc_free( esc ) ;
341 talloc_free( query ) ;
343 if ( result != NULL )
344 PQclear( result ) ;
346 return retval ;
349 /******************************************************************
350 Lookup a name in the SAM database
351 ******************************************************************/
353 static NTSTATUS pgsqlsam_getsampwnam ( struct pdb_methods *methods, SAM_ACCOUNT *user, const char *sname )
355 struct pdb_pgsql_data *data;
356 size_t i, l;
357 char *lowercasename;
358 NTSTATUS result;
360 SET_DATA(data, methods);
362 if ( !sname )
364 DEBUG( 0, ("invalid name specified") ) ;
365 return NT_STATUS_INVALID_PARAMETER;
368 lowercasename = smb_xstrdup(sname);
369 l = strlen(lowercasename);
370 for(i = 0; i < l; i++) {
371 lowercasename[i] = tolower(lowercasename[i]);
374 result = pgsqlsam_select_by_field( methods, user, SQL_SEARCH_USER_NAME, lowercasename ) ;
376 SAFE_FREE( lowercasename ) ;
378 return result;
382 /***************************************************************************
383 Search by sid
384 **************************************************************************/
386 static NTSTATUS pgsqlsam_getsampwsid ( struct pdb_methods *methods, SAM_ACCOUNT *user, const DOM_SID *sid )
388 struct pdb_pgsql_data *data;
389 fstring sid_str;
391 SET_DATA( data, methods ) ;
393 sid_to_string( sid_str, sid ) ;
395 return pgsqlsam_select_by_field( methods, user, SQL_SEARCH_USER_SID, sid_str ) ;
398 /***************************************************************************
399 Delete a SAM_ACCOUNT
400 ****************************************************************************/
402 static NTSTATUS pgsqlsam_delete_sam_account( struct pdb_methods *methods, SAM_ACCOUNT *sam_pass )
404 struct pdb_pgsql_data *data ;
405 PGconn *handle ;
407 const char *sname = pdb_get_username( sam_pass ) ;
408 char *esc ;
409 char *query ;
411 PGresult *result ;
412 NTSTATUS retval ;
414 SET_DATA(data, methods);
416 if ( !sname )
418 DEBUG( 0, ("invalid name specified\n") ) ;
419 return NT_STATUS_INVALID_PARAMETER ;
422 /* Escape sname */
423 esc = talloc_array(NULL, char, strlen(sname) * 2 + 1);
424 if ( !esc )
426 DEBUG(0, ("Can't allocate memory to store escaped name\n"));
427 return NT_STATUS_NO_MEMORY;
430 PQescapeString( esc, sname, strlen(sname) ) ;
432 /* Connect to the DB. */
433 handle = choose_connection( data );
434 if ( handle == NULL )
435 return NT_STATUS_UNSUCCESSFUL ;
437 query = sql_account_query_delete(NULL, data->location, esc);
439 /* Do it */
440 result = PQexec( handle, query ) ;
442 if ( result == NULL )
444 DEBUG( 0, ("Error executing %s, %s\n", query, PQerrorMessage( handle ) ) ) ;
445 retval = NT_STATUS_UNSUCCESSFUL ;
447 else if ( PQresultStatus( result ) != PGRES_COMMAND_OK )
449 DEBUG( 0, ("Error executing %s, %s\n", query, PQresultErrorMessage( result ) ) ) ;
450 retval = NT_STATUS_UNSUCCESSFUL ;
452 else
454 DEBUG( 5, ("User '%s' deleted\n", sname) ) ;
455 retval = NT_STATUS_OK ;
458 if ( result != NULL )
459 PQclear( result ) ;
460 talloc_free( esc ) ;
461 talloc_free( query ) ;
463 return retval ;
466 static NTSTATUS pgsqlsam_replace_sam_account( struct pdb_methods *methods, const SAM_ACCOUNT *newpwd, char isupdate )
468 struct pdb_pgsql_data *data ;
469 PGconn *handle ;
470 char *query;
471 PGresult *result ;
472 NTSTATUS retval ;
474 if ( !methods )
476 DEBUG( 0, ("invalid methods!\n") ) ;
477 return NT_STATUS_INVALID_PARAMETER ;
480 data = (struct pdb_pgsql_data *) methods->private_data ;
482 if ( data == NULL || handle == NULL )
484 DEBUG( 0, ("invalid handle!\n") ) ;
485 return NT_STATUS_INVALID_HANDLE ;
488 query = sql_account_query_update(NULL, data->location, newpwd, isupdate);
489 if ( query == NULL ) /* Nothing to update. */
490 return NT_STATUS_OK;
492 /* Connect to the DB. */
493 handle = choose_connection( data );
494 if ( handle == NULL )
495 return NT_STATUS_UNSUCCESSFUL ;
497 result = PQexec( handle, query ) ;
499 /* Execute the query */
500 if ( result == NULL )
502 DEBUG( 0, ("Error executing %s, %s\n", query, PQerrorMessage( handle ) ) ) ;
503 retval = NT_STATUS_INVALID_PARAMETER;
505 else if ( PQresultStatus( result ) != PGRES_COMMAND_OK )
507 DEBUG( 0, ("Error executing %s, %s\n", query, PQresultErrorMessage( result ) ) ) ;
508 retval = NT_STATUS_INVALID_PARAMETER;
510 else
512 retval = NT_STATUS_OK;
514 if ( result != NULL )
515 PQclear( result ) ;
516 talloc_free(query);
518 return retval;
521 static NTSTATUS pgsqlsam_add_sam_account ( struct pdb_methods *methods, SAM_ACCOUNT *newpwd )
523 return pgsqlsam_replace_sam_account( methods, newpwd, 0 ) ;
526 static NTSTATUS pgsqlsam_update_sam_account ( struct pdb_methods *methods, SAM_ACCOUNT *newpwd )
528 return pgsqlsam_replace_sam_account( methods, newpwd, 1 ) ;
531 static NTSTATUS pgsqlsam_init ( struct pdb_context *pdb_context, struct pdb_methods **pdb_method, const char *location )
533 NTSTATUS nt_status ;
534 struct pdb_pgsql_data *data ;
536 if ( !pdb_context )
538 DEBUG( 0, ("invalid pdb_methods specified\n") ) ;
539 return NT_STATUS_UNSUCCESSFUL;
542 the_pdb_context = pdb_context;
544 if (!NT_STATUS_IS_OK
545 (nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
546 return nt_status;
549 (*pdb_method)->name = "pgsqlsam" ;
551 (*pdb_method)->setsampwent = pgsqlsam_setsampwent ;
552 (*pdb_method)->endsampwent = pgsqlsam_endsampwent ;
553 (*pdb_method)->getsampwent = pgsqlsam_getsampwent ;
554 (*pdb_method)->getsampwnam = pgsqlsam_getsampwnam ;
555 (*pdb_method)->getsampwsid = pgsqlsam_getsampwsid ;
556 (*pdb_method)->add_sam_account = pgsqlsam_add_sam_account ;
557 (*pdb_method)->update_sam_account = pgsqlsam_update_sam_account ;
558 (*pdb_method)->delete_sam_account = pgsqlsam_delete_sam_account ;
560 data = talloc( pdb_context->mem_ctx, struct pdb_pgsql_data ) ;
561 (*pdb_method)->private_data = data ;
563 data->master_handle = NULL;
564 data->handle = NULL;
565 data->pwent = NULL ;
567 if ( !location )
569 DEBUG( 0, ("No identifier specified. Check the Samba HOWTO Collection for details\n") ) ;
570 return NT_STATUS_INVALID_PARAMETER;
573 data->location = smb_xstrdup( location ) ;
575 if(!sql_account_config_valid(data->location)) {
576 return NT_STATUS_INVALID_PARAMETER;
579 DEBUG
583 "Database server parameters: host: %s, user: %s, password: XXXX, database: %s, port: %s\n",
584 config_value( data, "pgsql host" , CONFIG_HOST_DEFAULT ),
585 config_value( data, "pgsql user" , CONFIG_USER_DEFAULT ),
586 config_value( data, "pgsql database", CONFIG_DB_DEFAULT ),
587 config_value( data, "pgsql port" , CONFIG_PORT_DEFAULT )
591 /* Save the parameters. */
592 data->db = config_value( data, "pgsql database", CONFIG_DB_DEFAULT );
593 data->host = config_value( data, "pgsql host" , CONFIG_HOST_DEFAULT );
594 data->port = config_value( data, "pgsql port" , CONFIG_PORT_DEFAULT );
595 data->user = config_value( data, "pgsql user" , CONFIG_USER_DEFAULT );
596 data->pass = config_value( data, "pgsql password", CONFIG_PASS_DEFAULT );
598 DEBUG( 5, ("Pgsql module intialized\n") ) ;
599 return NT_STATUS_OK;
602 NTSTATUS pdb_pgsql_init(void)
604 return smb_register_passdb( PASSDB_INTERFACE_VERSION, "pgsql", pgsqlsam_init ) ;