This commit was manufactured by cvs2svn to create tag
[Samba.git] / source / passdb / mysqlpass.c
blob75be8b638b9e9d14e94d418d6ade687028bd38d8
1 /*
2 * Unix SMB/Netbios implementation.
3 * Version 1.9.
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,
8 *
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)
26 #include "includes.h"
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 };
41 struct mysql_struct {
42 MYSQL handle;
43 MYSQL_RES *result;
44 uint current_row;
46 typedef struct mysql_struct mysql_ctrl;
48 static char *mysql_retrieve_password(char *passfile)
50 static fstring pass;
51 static time_t last_checked = (time_t)0;
52 static char pass_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_-+=|~`\\{}[]:;\"'?/>.<,";
53 fstring temppass;
54 FILE *filep;
55 int length;
57 DEBUG(5,("%s\n",FUNCTION_MACRO));
59 if ( passfile == NULL ) {
60 pass[0]=0;
61 return pass;
64 if ( time(NULL) - last_checked <= 60 ) {
65 return pass;
68 if ( file_modtime(passfile) < last_checked ) {
69 return pass;
72 filep = sys_fopen(passfile,"r");
74 if ( filep == NULL ) {
75 return pass;
78 memset(temppass,0,sizeof(temppass));
80 if ( fgets( temppass, sizeof(temppass)-1, filep) == NULL ) {
81 fclose(filep);
82 return pass;
85 fclose(filep);
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);
94 return pass;
97 static int mysql_db_connect( MYSQL *handle )
99 char *password;
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)));
107 return -1;
110 if ( mysql_select_db( handle, lp_mysql_db()) ) {
111 DEBUG(0,("mysql_connect: %s\n",mysql_error(handle)));
112 mysql_close(handle);
113 return -1;
116 fstrcpy(mysql_table,lp_mysql_table());
118 return 0;
121 static int mysql_lock_table( MYSQL *handle, BOOL write_access )
123 fstring query;
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) ));
131 return -1;
134 return 0;
137 int mysql_db_lock_connect( MYSQL *handle )
140 DEBUG(5,("%s\n",FUNCTION_MACRO));
142 if ( mysql_db_connect( handle ) ) {
143 return -1;
146 if ( mysql_lock_table( handle, True ) ) {
147 mysql_close( handle );
148 return -1;
151 return 0;
154 static MYSQL_RES *mysql_select_results( MYSQL *handle, char *selection )
156 MYSQL_RES *result;
157 pstring query;
158 int query_length;
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"));
174 return NULL;
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) ));
190 return NULL;
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 )));
197 return NULL;
200 if ( result == NULL ) {
201 DEBUG(0,("mysql_store_result: %s\n",mysql_error(handle)));
202 return NULL;
205 return result;
208 void *mysql_startpwent( BOOL update )
210 mysql_ctrl *mysql;
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"));
217 return NULL;
220 memset( mysql, 0, sizeof(mysql_ctrl) );
222 if ( mysql_db_connect( &mysql->handle ) ) {
223 return NULL;
226 if ( mysql_lock_table( &mysql->handle, update ) ) {
227 mysql_close( &mysql->handle );
228 return NULL;
231 mysql->result = mysql_select_results( &mysql->handle, NULL );
233 if ( mysql->result == NULL ) {
234 mysql_close( &mysql->handle );
235 return NULL;
238 mysql->current_row = 0;
240 return (void*)mysql;
243 void mysql_endpwent( void *ptr )
245 mysql_ctrl *handle;
247 DEBUG(5,("%s\n",FUNCTION_MACRO));
248 handle = (mysql_ctrl *)ptr;
250 mysql_free_result( handle->result );
252 mysql_close( &handle->handle );
254 free( 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;
273 return True;
276 static void quote_hash( char *target, unsigned char *passwd )
278 char hex[] = "0123456789ABCDEF";
279 int i;
281 DEBUG(5,("%s\n",FUNCTION_MACRO));
283 if ( passwd == NULL ) {
284 fstrcpy(target,"NULL");
286 else {
287 target[0]='\'';
288 for (i=0;i<32;i++) {
289 target[i+1] = hex[(passwd[i>>1]>>(((~i)&1)<<2))&15];
291 target[33] = '\'';
292 target[34] = '\0';
296 static unsigned char *decode_hash( char *hash, unsigned char *buffer )
298 char hex[] = "0123456789ABCDEF";
299 int pos, v1, v2;
301 DEBUG(5,("%s\n",FUNCTION_MACRO));
303 if ( hash == NULL ) {
304 return 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) ) {
312 return NULL;
315 buffer[pos] = (v1<<4)|v2;
316 hash += 2;
319 return buffer;
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 ));
350 return NULL;
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)
370 mysql_ctrl *mysql;
371 static MYSQL_ROW row;
373 DEBUG(5,("%s\n",FUNCTION_MACRO));
375 mysql = (mysql_ctrl*)vp;
376 row = mysql_fetch_row( mysql->result );
378 if ( row == NULL ) {
379 return NULL;
382 mysql->current_row++;
384 return &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 )
397 void *retval;
398 MYSQL handle;
399 MYSQL_RES *result;
400 MYSQL_ROW row;
402 DEBUG(5,("%s\n",FUNCTION_MACRO));
404 if ( filler == NULL ) {
405 return NULL;
408 if ( where == NULL || *where == '\0' ) {
409 DEBUG(0,("Null or empty query\n"));
410 return NULL;
413 if ( mysql_db_connect( &handle ) ) {
414 return NULL;
417 result = mysql_select_results( &handle, where );
418 if ( result == NULL ) {
419 mysql_close( &handle );
420 return NULL;
423 row = mysql_fetch_row ( result );
424 if ( row == NULL ) {
425 mysql_free_result( result );
426 mysql_close( &handle );
427 return NULL;
430 if ( DEBUGLEVEL >= 7 ) {
431 int field;
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 );
442 return retval;
445 void *mysql_getpwuid(void *(*filler)(MYSQL_ROW *), uid_t uid)
447 fstring where;
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)
466 fstring where;
467 char format[] = "%s='%s'";
469 DEBUG(5,("%s\n",FUNCTION_MACRO));
471 if ( filler == NULL ) {
472 DEBUG(0,("Empty fill opteration\n"));
473 return NULL;
476 if ( field == NULL || *field == '\0' ) {
477 DEBUG(0,("Empty or NULL field name\n"));
478 return NULL;
481 if ( name == NULL || *name == '\0' ) {
482 DEBUG(0,("Empty or NULL query\n"));
483 return NULL;
486 if ( sizeof(format) + strlen(name) + strlen(field) > sizeof(where) ) {
487 DEBUG(0,("Query string too long\n"));
488 return NULL;
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" );
510 else {
511 target[0] = '\'';
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 )
519 pstring query;
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)) {
525 return False;
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) ));
532 return False;
535 return True;
538 BOOL mysql_add_smb( MYSQL *handle, struct smb_passwd *smb )
540 pstring query;
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"));
547 return False;
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) ));
554 return False;
557 return True;
560 BOOL mysql_mod_smb( MYSQL *handle, struct smb_passwd *smb, BOOL override )
562 pstring query;
563 fstring smb_passwd;
564 fstring smb_nt_passwd;
565 fstring nt_name;
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"));
574 return False;
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) ));
590 return False;
593 if ( mysql_affected_rows( handle ) < 1 ) {
594 DEBUG(3,("No entries changed\n"));
595 return False;
598 return True;
601 BOOL mysql_add_smbpwd_entry(struct smb_passwd *smb)
603 MYSQL handle;
605 DEBUG(5,("%s\n",FUNCTION_MACRO));
607 if ( smb == NULL ) {
608 return False;
611 if ( mysql_db_lock_connect( &handle ) ) {
612 return False;
615 if ( !mysql_add_smb( &handle, smb ) ) {
616 mysql_close( &handle );
617 return False;
620 if ( !mysql_mod_smb( &handle, smb, True ) ) {
621 mysql_del_smb( &handle, smb->unix_name );
622 mysql_close( &handle );
623 return False;
626 mysql_close(&handle);
627 return True;
630 BOOL mysql_mod_smbpwd_entry(struct smb_passwd *smb, BOOL override)
632 MYSQL handle;
634 DEBUG(5,("%s\n",FUNCTION_MACRO));
636 if ( smb == NULL ) {
637 return False;
640 if ( mysql_db_lock_connect( &handle ) ) {
641 return False;
644 if ( !mysql_mod_smb( &handle, smb, override ) ) {
645 mysql_close(&handle);
646 return False;
649 mysql_close(&handle);
650 return True;
653 static struct smb_passdb_ops mysql_ops = {
654 mysql_startpwent,
655 mysql_endpwent,
656 mysql_getpwpos,
657 mysql_setpwpos,
658 mysql_getsmbpwnam,
659 mysql_getsmbpwuid,
660 mysql_getsmbpwent,
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);
668 return &mysql_ops;
671 #else
672 void mysql_dummy_smb_function(void) { }
673 #endif