2 * Unix SMB/Netbios implementation.
4 * Samba MYSQL SAM Database, by Benjamin Kuit.
5 * Copyright (C) Benjamin Kuit 1999,
6 * Copyright (C) Andrew Tridgell 1992-1999,
7 * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #if defined(HAVE_MYSQL_H) && defined(WITH_MYSQLSAM)
28 extern int DEBUGLEVEL
;
30 #define UNIX_NAME(row) ((*row)[0])
31 #define UNIX_UID(row) ((*row)[1])
32 #define NT_NAME(row) ((*row)[2])
33 #define RID(row) ((*row)[3])
34 #define LM_HASH(row) ((*row)[4])
35 #define NT_HASH(row) ((*row)[5])
36 #define FLAGS(row) ((*row)[6])
37 #define CHANGE_TIME(row) ((*row)[7])
39 static fstring mysql_table
= { 0 };
46 typedef struct mysql_struct mysql_ctrl
;
48 static char *mysql_retrieve_password(char *passfile
)
51 static time_t last_checked
= (time_t)0;
52 static char pass_chars
[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_-+=|~`\\{}[]:;\"'?/>.<,";
57 DEBUG(5,("%s\n",FUNCTION_MACRO
));
59 if ( passfile
== NULL
) {
64 if ( time(NULL
) - last_checked
<= 60 ) {
68 if ( file_modtime(passfile
) < last_checked
) {
72 filep
= sys_fopen(passfile
,"r");
74 if ( filep
== NULL
) {
78 memset(temppass
,0,sizeof(temppass
));
80 if ( fgets( temppass
, sizeof(temppass
)-1, filep
) == NULL
) {
87 length
= strspn( temppass
, pass_chars
);
88 temppass
[length
<sizeof(temppass
)-1?length
:sizeof(temppass
)-1] = '\0';
90 fstrcpy( pass
, temppass
);
92 last_checked
= time(NULL
);
97 static int mysql_db_connect( MYSQL
*handle
)
101 DEBUG(5,("%s\n",FUNCTION_MACRO
));
103 password
= mysql_retrieve_password(lp_mysql_passfile());
105 if ( !mysql_connect(handle
, lp_mysql_host(), lp_mysql_user(), password
) ) {
106 DEBUG(0,("mysql_connect: %s\n",mysql_error(handle
)));
110 if ( mysql_select_db( handle
, lp_mysql_db()) ) {
111 DEBUG(0,("mysql_connect: %s\n",mysql_error(handle
)));
116 fstrcpy(mysql_table
,lp_mysql_table());
121 static int mysql_lock_table( MYSQL
*handle
, BOOL write_access
)
125 DEBUG(5,("%s\n",FUNCTION_MACRO
));
127 slprintf( query
, sizeof(query
), "lock tables %s %s", mysql_table
, write_access
==True
?"write":"read");
129 if ( mysql_query( handle
, query
) ) {
130 DEBUG(0,("Cannot get lock: %s: %s\n",query
,mysql_error(handle
) ));
137 int mysql_db_lock_connect( MYSQL
*handle
)
140 DEBUG(5,("%s\n",FUNCTION_MACRO
));
142 if ( mysql_db_connect( handle
) ) {
146 if ( mysql_lock_table( handle
, True
) ) {
147 mysql_close( handle
);
154 static MYSQL_RES
*mysql_select_results( MYSQL
*handle
, char *selection
)
159 char select
[] = "select ";
160 char where
[] = " where ";
161 char from
[] = " from ";
162 char mysql_query_string
[] = "unix_name, unix_uid, nt_name, user_rid, smb_passwd, smb_nt_passwd, acct_ctrl, pass_last_set_time";
164 DEBUG(5,("%s\n",FUNCTION_MACRO
));
166 query_length
= sizeof( select
) + sizeof( mysql_query_string
) + sizeof(from
) + strlen( mysql_table
);
168 if ( selection
!= NULL
&& *selection
!= '\0' ) {
169 query_length
+= sizeof( where
) + strlen( selection
);
172 if ( query_length
>= sizeof( query
) ) {
173 DEBUG(0,("Query string too long\n"));
177 pstrcpy( query
, select
);
178 pstrcat( query
, mysql_query_string
);
179 pstrcat( query
, from
);
180 pstrcat( query
, mysql_table
);
182 if ( selection
!= NULL
&& *selection
!= '\0' ) {
183 pstrcat( query
, where
);
184 pstrcat( query
, selection
);
187 DEBUG(5,("mysql> %s\n",query
));
188 if ( mysql_query( handle
, query
) ) {
189 DEBUG(0,("%s: %s\n", query
, mysql_error(handle
) ));
193 result
= mysql_store_result( handle
);
195 if ( mysql_num_fields( result
) != 8 ) {
196 DEBUG(0,("mysql_num_result = %d (!=8)\n",mysql_num_fields( result
)));
200 if ( result
== NULL
) {
201 DEBUG(0,("mysql_store_result: %s\n",mysql_error(handle
)));
208 void *mysql_startpwent( BOOL update
)
212 DEBUG(5,("%s\n",FUNCTION_MACRO
));
214 mysql
= (mysql_ctrl
*)malloc( sizeof(mysql_ctrl
) );
215 if ( mysql
== NULL
) {
216 DEBUG(0,("malloc: Out of memory\n"));
220 memset( mysql
, 0, sizeof(mysql_ctrl
) );
222 if ( mysql_db_connect( &mysql
->handle
) ) {
226 if ( mysql_lock_table( &mysql
->handle
, update
) ) {
227 mysql_close( &mysql
->handle
);
231 mysql
->result
= mysql_select_results( &mysql
->handle
, NULL
);
233 if ( mysql
->result
== NULL
) {
234 mysql_close( &mysql
->handle
);
238 mysql
->current_row
= 0;
243 void mysql_endpwent( void *ptr
)
247 DEBUG(5,("%s\n",FUNCTION_MACRO
));
248 handle
= (mysql_ctrl
*)ptr
;
250 mysql_free_result( handle
->result
);
252 mysql_close( &handle
->handle
);
257 SMB_BIG_UINT
mysql_getpwpos(void *vp
)
260 DEBUG(5,("%s\n",FUNCTION_MACRO
));
262 return ((mysql_ctrl
*)vp
)->current_row
;
265 BOOL
mysql_setpwpos(void *vp
, SMB_BIG_UINT pos
)
268 DEBUG(5,("%s\n",FUNCTION_MACRO
));
270 mysql_data_seek( ((mysql_ctrl
*)vp
)->result
, (uint
)pos
);
271 ((mysql_ctrl
*)vp
)->current_row
=(uint
)pos
;
276 static void quote_hash( char *target
, unsigned char *passwd
)
278 char hex
[] = "0123456789ABCDEF";
281 DEBUG(5,("%s\n",FUNCTION_MACRO
));
283 if ( passwd
== NULL
) {
284 fstrcpy(target
,"NULL");
289 target
[i
+1] = hex
[(passwd
[i
>>1]>>(((~i
)&1)<<2))&15];
296 static unsigned char *decode_hash( char *hash
, unsigned char *buffer
)
298 char hex
[] = "0123456789ABCDEF";
301 DEBUG(5,("%s\n",FUNCTION_MACRO
));
303 if ( hash
== NULL
) {
307 for (pos
=0;pos
<16;pos
++) {
308 for( v1
= 0; v1
< sizeof(hex
) && hash
[0] != hex
[v1
]; v1
++ );
309 for( v2
= 0; v2
< sizeof(hex
) && hash
[1] != hex
[v2
]; v2
++ );
311 if ( v1
== sizeof(hex
) || v2
== sizeof(hex
) ) {
315 buffer
[pos
] = (v1
<<4)|v2
;
322 void *mysql_fill_smb_passwd( MYSQL_ROW
*row
)
324 static struct smb_passwd pw_buf
;
325 static fstring unix_name
;
326 static fstring nt_name
;
327 static unsigned char smbpwd
[16];
328 static unsigned char smbntpwd
[16];
330 DEBUG(5,("%s\n",FUNCTION_MACRO
));
332 pwdb_init_smb(&pw_buf
);
334 fstrcpy( unix_name
, UNIX_NAME(row
) );
335 pw_buf
.unix_name
= unix_name
;
336 pw_buf
.unix_uid
= get_number( UNIX_UID(row
) );
338 if ( NT_NAME(row
) != NULL
) {
339 fstrcpy( nt_name
, NT_NAME(row
) );
340 pw_buf
.nt_name
= nt_name
;
343 if ( RID(row
) != NULL
) {
344 pw_buf
.user_rid
= get_number( RID(row
) );
347 pw_buf
.smb_passwd
= decode_hash( LM_HASH(row
), smbpwd
);
348 if ( !pw_buf
.smb_passwd
) {
349 DEBUG(4, ("entry invalidated for unix user %s\n", unix_name
));
353 pw_buf
.smb_nt_passwd
= decode_hash( NT_HASH(row
), smbntpwd
);
355 if ( FLAGS(row
) != NULL
) {
356 pw_buf
.acct_ctrl
= get_number( FLAGS(row
) );
359 if ( pw_buf
.acct_ctrl
== 0 ) {
360 pw_buf
.acct_ctrl
= ACB_NORMAL
;
363 pw_buf
.pass_last_set_time
= get_number( CHANGE_TIME(row
) );
365 return (void*)&pw_buf
;
368 MYSQL_ROW
*mysql_getpwent(void *vp
)
371 static MYSQL_ROW row
;
373 DEBUG(5,("%s\n",FUNCTION_MACRO
));
375 mysql
= (mysql_ctrl
*)vp
;
376 row
= mysql_fetch_row( mysql
->result
);
382 mysql
->current_row
++;
387 struct smb_passwd
*mysql_getsmbpwent(void *vp
)
390 DEBUG(5,("%s\n",FUNCTION_MACRO
));
392 return (struct smb_passwd
*)mysql_fill_smb_passwd( mysql_getpwent(vp
) );
395 void *mysql_fetch_passwd( void *(*filler
)(MYSQL_ROW
*), char *where
)
402 DEBUG(5,("%s\n",FUNCTION_MACRO
));
404 if ( filler
== NULL
) {
408 if ( where
== NULL
|| *where
== '\0' ) {
409 DEBUG(0,("Null or empty query\n"));
413 if ( mysql_db_connect( &handle
) ) {
417 result
= mysql_select_results( &handle
, where
);
418 if ( result
== NULL
) {
419 mysql_close( &handle
);
423 row
= mysql_fetch_row ( result
);
425 mysql_free_result( result
);
426 mysql_close( &handle
);
430 if ( DEBUGLEVEL
>= 7 ) {
432 for (field
=0; field
< mysql_num_fields( result
); field
++ ) {
433 DEBUG(7,(" row[%d] = \"%s\"\n",field
,row
[field
]?row
[field
]:"NULL"));
437 retval
= (*filler
)( &row
);
439 mysql_free_result( result
);
440 mysql_close( &handle
);
445 void *mysql_getpwuid(void *(*filler
)(MYSQL_ROW
*), uid_t uid
)
449 DEBUG(5,("%s\n",FUNCTION_MACRO
));
451 slprintf( where
, sizeof(where
), "unix_uid=%lu", uid
);
453 return mysql_fetch_passwd(filler
,where
);
456 struct smb_passwd
*mysql_getsmbpwuid(uid_t uid
)
459 DEBUG(5,("%s\n",FUNCTION_MACRO
));
461 return (struct smb_passwd
*)mysql_getpwuid( mysql_fill_smb_passwd
, uid
);
464 void *mysql_getpwnam(void *(*filler
)(MYSQL_ROW
*), char *field
, const char *name
)
467 char format
[] = "%s='%s'";
469 DEBUG(5,("%s\n",FUNCTION_MACRO
));
471 if ( filler
== NULL
) {
472 DEBUG(0,("Empty fill opteration\n"));
476 if ( field
== NULL
|| *field
== '\0' ) {
477 DEBUG(0,("Empty or NULL field name\n"));
481 if ( name
== NULL
|| *name
== '\0' ) {
482 DEBUG(0,("Empty or NULL query\n"));
486 if ( sizeof(format
) + strlen(name
) + strlen(field
) > sizeof(where
) ) {
487 DEBUG(0,("Query string too long\n"));
491 slprintf(where
, sizeof( where
), format
, field
, name
);
493 return mysql_fetch_passwd( filler
, where
);
496 struct smb_passwd
*mysql_getsmbpwnam(const char *unix_name
)
498 DEBUG(5,("%s\n",FUNCTION_MACRO
));
500 return mysql_getpwnam( mysql_fill_smb_passwd
, "unix_name", unix_name
);
503 static void quote_string(char *target
, char *string
)
505 DEBUG(5,("%s\n",FUNCTION_MACRO
));
507 if ( string
== NULL
) {
508 fstrcpy( target
, "NULL" );
512 safe_strcpy(&target
[1],string
,sizeof(fstring
)-2);
513 safe_strcpy(&target
[strlen(target
)],"'",2);
517 BOOL
mysql_del_smb( MYSQL
*handle
, char *unix_name
)
520 char format
[] = "delete from %s where unix_name='%s'";
522 DEBUG(5,("%s\n",FUNCTION_MACRO
));
524 if (strlen( format
) + strlen(mysql_table
) + strlen(unix_name
)) {
528 slprintf( query
, sizeof(query
), format
, mysql_table
, unix_name
);
530 if ( mysql_query( handle
, query
) ) {
531 DEBUG(0,("%s: %s\n", query
, mysql_error(handle
) ));
538 BOOL
mysql_add_smb( MYSQL
*handle
, struct smb_passwd
*smb
)
541 char format
[] = "insert into %s (unix_name, unix_uid) values ( '%s', %lu )";
543 DEBUG(5,("%s\n",FUNCTION_MACRO
));
545 if ( strlen(format
) + strlen(mysql_table
) + strlen(smb
->unix_name
) + 10 > sizeof(query
) ) {
546 DEBUG(0,("Query too long\n"));
550 slprintf( query
, sizeof(query
), "insert into %s (unix_name,unix_uid) values ('%s', %lu)", mysql_table
, smb
->unix_name
, smb
->unix_uid
);
552 if ( mysql_query( handle
, query
) ) {
553 DEBUG(0,("%s: %s\n",query
,mysql_error(handle
) ));
560 BOOL
mysql_mod_smb( MYSQL
*handle
, struct smb_passwd
*smb
, BOOL override
)
564 fstring smb_nt_passwd
;
567 char format
[] = "update %s set nt_name=%s, user_rid=%lu, smb_passwd=%s, smb_nt_passwd=%s, acct_ctrl=%u, pass_last_set_time=unix_timestamp() where unix_name='%s'";
568 char extra
[] = " and not ISNULL(smb_passwd)";
570 DEBUG(5,("%s\n",FUNCTION_MACRO
));
572 if ( strlen(format
) + 2*20 + 3*10 + 2*32 + strlen(mysql_table
) >= sizeof( query
) + strlen( extra
) ) {
573 DEBUG(0,("Query string too long\n"));
577 quote_hash(smb_passwd
, smb
->smb_passwd
);
578 quote_hash(smb_nt_passwd
, smb
->smb_nt_passwd
);
580 quote_string(nt_name
, smb
->nt_name
);
582 slprintf( query
, sizeof(query
), format
, mysql_table
, nt_name
, (long unsigned)smb
->user_rid
, smb_passwd
, smb_nt_passwd
, smb
->acct_ctrl
, smb
->unix_name
);
584 if ( override
!= True
) {
585 pstrcat( query
, extra
);
588 if ( mysql_query( handle
, query
) ) {
589 DEBUG(0,("%s: %s\n",query
,mysql_error(handle
) ));
593 if ( mysql_affected_rows( handle
) < 1 ) {
594 DEBUG(3,("No entries changed\n"));
601 BOOL
mysql_add_smbpwd_entry(struct smb_passwd
*smb
)
605 DEBUG(5,("%s\n",FUNCTION_MACRO
));
611 if ( mysql_db_lock_connect( &handle
) ) {
615 if ( !mysql_add_smb( &handle
, smb
) ) {
616 mysql_close( &handle
);
620 if ( !mysql_mod_smb( &handle
, smb
, True
) ) {
621 mysql_del_smb( &handle
, smb
->unix_name
);
622 mysql_close( &handle
);
626 mysql_close(&handle
);
630 BOOL
mysql_mod_smbpwd_entry(struct smb_passwd
*smb
, BOOL override
)
634 DEBUG(5,("%s\n",FUNCTION_MACRO
));
640 if ( mysql_db_lock_connect( &handle
) ) {
644 if ( !mysql_mod_smb( &handle
, smb
, override
) ) {
645 mysql_close(&handle
);
649 mysql_close(&handle
);
653 static struct smb_passdb_ops mysql_ops
= {
661 mysql_add_smbpwd_entry
,
662 mysql_mod_smbpwd_entry
665 struct smb_passdb_ops
*mysql_initialise_password_db(void)
667 (void*)mysql_retrieve_password(NULL
);
672 void mysql_dummy_smb_function(void) { }