diff options
-rw-r--r-- | source3/Makefile.in | 4 | ||||
-rw-r--r-- | source3/libsmb/clientgen.c | 2 | ||||
-rw-r--r-- | source3/param/loadparm.c | 30 | ||||
-rw-r--r-- | source3/passdb/mysqlpass.c | 668 | ||||
-rw-r--r-- | source3/passdb/mysqlsampass.c | 265 | ||||
-rw-r--r-- | source3/passdb/passdb.c | 2 | ||||
-rw-r--r-- | source3/passdb/sampassdb.c | 2 | ||||
-rw-r--r-- | source3/script/mysql_convert.pl | 364 |
8 files changed, 1335 insertions, 2 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 8e00b91657..6e58774533 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -160,11 +160,11 @@ GROUPDB_OBJ = groupdb/groupdb.o groupdb/aliasdb.o groupdb/builtindb.o \ passdb/passgrp.o passdb/smbpassgroup.o \ passdb/smbpassgroupunix.o passdb/passgrpldap.o -SAMPASSDB_OBJ = passdb/sampassdb.o passdb/sampass.o passdb/sampassldap.o +SAMPASSDB_OBJ = passdb/sampassdb.o passdb/sampass.o passdb/sampassldap.o passdb/mysqlsampass.o PASSDB_OBJ = passdb/passdb.o passdb/smbpassfile.o passdb/smbpass.o \ passdb/pass_check.o passdb/ldap.o passdb/nispass.o \ - passdb/smbpasschange.o \ + passdb/smbpasschange.o passdb/mysqlpass.o \ lib/util_pwdb.o lib/domain_namemap.o lib/sids.o SMBD_OBJ1 = smbd/server.o smbd/files.o smbd/chgpasswd.o smbd/connection.o \ diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 60498c8fb2..e188cb3b99 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -679,6 +679,8 @@ prots[] = {PROTOCOL_LANMAN2,"Samba"}, {PROTOCOL_NT1,"NT LANMAN 1.0"}, {PROTOCOL_NT1,"NT LM 0.12"}, +#if 0 +#endif {-1,NULL} }; diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 8f92af90a9..845c2bd4e8 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -231,6 +231,13 @@ typedef struct BOOL bNTPipeSupport; BOOL bStatCache; BOOL bKernelOplocks; +#if defined(WITH_MYSQL) || defined(WITH_MYSQLSAM) + char *sMysqlDatabase; + char *sMysqlTable; + char *sMysqlUser; + char *sMysqlHost; + char *sMysqlPassFile; +#endif } global; static global Globals; @@ -747,6 +754,14 @@ static struct parm_struct parm_table[] = {"ldap passwd file", P_STRING, P_GLOBAL, &Globals.szLdapPasswdFile, NULL, NULL, 0}, #endif /* WITH_LDAP */ +#if defined(WITH_MYSQL) || defined(WITH_MYSQLSAM) + {"MySQL Options", P_SEP, P_SEPARATOR}, + {"mysql host", P_STRING, P_GLOBAL, &Globals.sMysqlHost, NULL, NULL, 0}, + {"mysql user", P_STRING, P_GLOBAL, &Globals.sMysqlUser, NULL, NULL, 0}, + {"mysql pass file", P_STRING, P_GLOBAL, &Globals.sMysqlPassFile, NULL, NULL, 0}, + {"mysql database", P_STRING, P_GLOBAL, &Globals.sMysqlDatabase, NULL, NULL, 0}, + {"mysql table", P_STRING, P_GLOBAL, &Globals.sMysqlTable, NULL, NULL, 0}, +#endif /* WITH_MYSQL */ {"Miscellaneous Options", P_SEP, P_SEPARATOR}, @@ -971,6 +986,14 @@ static void init_globals(void) */ Globals.bKernelOplocks = True; +#if defined(WITH_MYSQL) || defined(WITH_MYSQLSAM) + string_set(&Globals.sMysqlHost,"localhost"); + string_set(&Globals.sMysqlUser,"root"); + string_set(&Globals.sMysqlPassFile,NULL); + string_set(&Globals.sMysqlDatabase,"samba"); + string_set(&Globals.sMysqlTable,"smbpasswd"); +#endif + /* * This must be done last as it checks the value in * client_code_page. @@ -1329,6 +1352,13 @@ FN_LOCAL_INTEGER(lp_printing,iPrinting) FN_LOCAL_CHAR(lp_magicchar,magic_char) +#if defined(WITH_MYSQL) || defined(WITH_MYSQLSAM) +FN_GLOBAL_STRING(lp_mysql_host,&Globals.sMysqlHost) +FN_GLOBAL_STRING(lp_mysql_user,&Globals.sMysqlUser) +FN_GLOBAL_STRING(lp_mysql_passfile,&Globals.sMysqlPassFile) +FN_GLOBAL_STRING(lp_mysql_db,&Globals.sMysqlDatabase) +FN_GLOBAL_STRING(lp_mysql_table,&Globals.sMysqlTable) +#endif /* local prototypes */ diff --git a/source3/passdb/mysqlpass.c b/source3/passdb/mysqlpass.c new file mode 100644 index 0000000000..90a6011692 --- /dev/null +++ b/source3/passdb/mysqlpass.c @@ -0,0 +1,668 @@ +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * Samba MYSQL SAM Database, by Benjamin Kuit. + * Copyright (C) Benjamin Kuit 1999, + * Copyright (C) Andrew Tridgell 1992-1999, + * Copyright (C) Luke Kenneth Casson Leighton 1996-1998, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if defined(WITH_MYSQL) || defined(WITH_MYSQLSAM) + +#include "includes.h" +#include <mysql.h> + +extern int DEBUGLEVEL; + +#define UNIX_NAME(row) ((*row)[0]) +#define UNIX_UID(row) ((*row)[1]) +#define NT_NAME(row) ((*row)[2]) +#define RID(row) ((*row)[3]) +#define LM_HASH(row) ((*row)[4]) +#define NT_HASH(row) ((*row)[5]) +#define FLAGS(row) ((*row)[6]) +#define CHANGE_TIME(row) ((*row)[7]) + +void *mysql_fill_smb_passwd( MYSQL_ROW *row ); + +typedef void *(*mysql_fill_func)( MYSQL_ROW * ); +#define FILL_SMB mysql_fill_smb_passwd + +void *mysql_startpwent(BOOL update); +void mysql_endpwent(void *vp); +SMB_BIG_UINT mysql_getpwpos(void *vp); +BOOL mysql_setpwpos(void *vp, SMB_BIG_UINT pos); +void *mysql_fill_smb_passwd( MYSQL_ROW *row ); +MYSQL_ROW *mysql_getpwent(void *vp); +void *mysql_fetch_passwd( mysql_fill_func filler, char *where ); +void *mysql_getpwuid( mysql_fill_func filler, uid_t uid ); +void *mysql_getpwnam( mysql_fill_func filler, char *field, const char *name ); +int mysql_db_lock_connect( MYSQL *handle ); +BOOL mysql_add_smb( MYSQL *handle, struct smb_passwd *smb ); +BOOL mysql_mod_smb( MYSQL *handle, struct smb_passwd *smb, BOOL override ); +BOOL mysql_del_smb( MYSQL *handle, char *unix_name ); + +static fstring mysql_table = { 0 }; + +struct mysql_struct { + MYSQL handle; + MYSQL_RES *result; + uint current_row; +}; +typedef struct mysql_struct mysql_ctrl; + +static char *mysql_retrieve_password(char *passfile) { + static fstring pass; + static time_t last_checked = (time_t)0; + static char pass_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_-+=|~`\\{}[]:;\"'?/>.<,"; + fstring temppass; + FILE *filep; + int length; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + if ( passfile == NULL ) { + pass[0]=0; + return pass; + } + + if ( time(NULL) - last_checked <= 60 ) { + return pass; + } + + if ( file_modtime(passfile) < last_checked ) { + return pass; + } + + filep = sys_fopen(passfile,"r"); + + if ( filep == NULL ) { + return pass; + } + + memset(temppass,0,sizeof(temppass)); + + if ( fgets( temppass, sizeof(temppass)-1, filep) == NULL ) { + fclose(filep); + return pass; + } + + fclose(filep); + + length = strspn( temppass, pass_chars ); + temppass[length<sizeof(temppass)-1?length:sizeof(temppass)-1] = '\0'; + + fstrcpy( pass, temppass ); + + last_checked = time(NULL); + + return pass; +} + +static int mysql_db_connect( MYSQL *handle ) { + char *password; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + password = mysql_retrieve_password(lp_mysql_passfile()); + + if ( !mysql_connect(handle, lp_mysql_host(), lp_mysql_user(), password) ) { + DEBUG(0,("mysql_connect: %s\n",mysql_error(handle))); + return -1; + } + + if ( mysql_select_db( handle, lp_mysql_db()) ) { + DEBUG(0,("mysql_connect: %s\n",mysql_error(handle))); + mysql_close(handle); + return -1; + } + + fstrcpy(mysql_table,lp_mysql_table()); + + return 0; +} + +static int mysql_lock_table( MYSQL *handle, BOOL write_access ) { + fstring query; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + slprintf( query, sizeof(query), "lock tables %s %s", mysql_table, write_access==True?"write":"read"); + + if ( mysql_query( handle, query ) ) { + DEBUG(0,("Cannot get lock: %s: %s\n",query,mysql_error(handle) )); + return -1; + } + + return 0; +} + +int mysql_db_lock_connect( MYSQL *handle ) { + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + if ( mysql_db_connect( handle ) ) { + return -1; + } + + if ( mysql_lock_table( handle, True ) ) { + mysql_close( handle ); + return -1; + } + + return 0; +} + +static MYSQL_RES *mysql_select_results( MYSQL *handle, char *selection ) { + MYSQL_RES *result; + pstring query; + int query_length; + char select[] = "select "; + char where[] = " where "; + char from[] = " from "; + char mysql_query_string[] = "unix_name, unix_uid, nt_name, user_rid, smb_passwd, smb_nt_passwd, acct_ctrl, pass_last_set_time"; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + query_length = sizeof( select ) + sizeof( mysql_query_string ) + sizeof(from ) + strlen( mysql_table ); + + if ( selection != NULL && *selection != '\0' ) { + query_length += sizeof( where ) + strlen( selection ); + } + + if ( query_length >= sizeof( query ) ) { + DEBUG(0,("Query string too long\n")); + return NULL; + } + + pstrcpy( query, select); + pstrcat( query, mysql_query_string ); + pstrcat( query, from ); + pstrcat( query, mysql_table ); + + if ( selection != NULL && *selection != '\0' ) { + pstrcat( query, where ); + pstrcat( query, selection ); + } + + DEBUG(5,("mysql> %s\n",query)); + if ( mysql_query( handle, query ) ) { + DEBUG(0,("%s: %s\n", query, mysql_error(handle) )); + return NULL; + } + + result = mysql_store_result( handle ); + + if ( mysql_num_fields( result ) != 8 ) { + DEBUG(0,("mysql_num_result = %d (!=8)\n",mysql_num_fields( result ))); + return NULL; + } + + if ( result == NULL ) { + DEBUG(0,("mysql_store_result: %s\n",mysql_error(handle))); + return NULL; + } + + return result; +} + +void *mysql_startpwent( BOOL update ) { + mysql_ctrl *mysql; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + mysql = (mysql_ctrl *)malloc( sizeof(mysql_ctrl) ); + if ( mysql == NULL ) { + DEBUG(0,("malloc: Out of memory\n")); + return NULL; + } + + memset( mysql, 0, sizeof(mysql_ctrl) ); + + if ( mysql_db_connect( &mysql->handle ) ) { + return NULL; + } + + if ( mysql_lock_table( &mysql->handle, update ) ) { + mysql_close( &mysql->handle ); + return NULL; + } + + mysql->result = mysql_select_results( &mysql->handle, NULL ); + + if ( mysql->result == NULL ) { + mysql_close( &mysql->handle ); + return NULL; + } + + mysql->current_row = 0; + + return (void*)mysql; +} + +void mysql_endpwent( void *ptr ) { + mysql_ctrl *handle; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + handle = (mysql_ctrl *)ptr; + + mysql_free_result( handle->result ); + + mysql_close( &handle->handle ); + + free( handle ); +} + +SMB_BIG_UINT mysql_getpwpos(void *vp) { + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + return ((mysql_ctrl *)vp)->current_row; +} + +BOOL mysql_setpwpos(void *vp, SMB_BIG_UINT pos) { + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + mysql_data_seek( ((mysql_ctrl*)vp)->result, (uint)pos ); +((mysql_ctrl *)vp)->current_row=(uint)pos; + + return True; +} + +static void quote_hash( char *target, unsigned char *passwd ) { + char hex[] = "0123456789ABCDEF"; + int i; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + if ( passwd == NULL ) { + fstrcpy(target,"NULL"); + } + else { + target[0]='\''; + for (i=0;i<32;i++) { + target[i+1] = hex[(passwd[i>>1]>>(((~i)&1)<<2))&15]; + } + target[33] = '\''; + target[34] = '\0'; + } +} + +static unsigned char *decode_hash( char *hash, unsigned char *buffer ) { + char hex[] = "0123456789ABCDEF"; + int pos, v1, v2; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + if ( hash == NULL ) { + return NULL; + } + + for (pos=0;pos<16;pos++) { + for( v1 = 0; v1 < sizeof(hex) && hash[0] != hex[v1]; v1++ ); + for( v2 = 0; v2 < sizeof(hex) && hash[1] != hex[v2]; v2++ ); + + if ( v1 == sizeof(hex) || v2 == sizeof(hex) ) { + return NULL; + } + + buffer[pos] = (v1<<4)|v2; + hash += 2; + } + + return buffer; +} + +void *mysql_fill_smb_passwd( MYSQL_ROW *row ) { + static struct smb_passwd pw_buf; + static fstring unix_name; + static fstring nt_name; + static unsigned char smbpwd[16]; + static unsigned char smbntpwd[16]; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + pwdb_init_smb(&pw_buf); + + fstrcpy( unix_name, UNIX_NAME(row) ); + pw_buf.unix_name = unix_name; + pw_buf.unix_uid = get_number( UNIX_UID(row) ); + + if ( NT_NAME(row) != NULL ) { + fstrcpy( nt_name, NT_NAME(row) ); + pw_buf.nt_name = nt_name; + } + + if ( RID(row) != NULL ) { + pw_buf.user_rid = get_number( RID(row) ); + } + + pw_buf.smb_passwd = decode_hash( LM_HASH(row), smbpwd ); + if ( !pw_buf.smb_passwd ) { + DEBUG(4, ("entry invalidated for unix user %s\n", unix_name )); + return NULL; + } + + pw_buf.smb_nt_passwd = decode_hash( NT_HASH(row), smbntpwd ); + + if ( FLAGS(row) != NULL ) { + pw_buf.acct_ctrl = get_number( FLAGS(row) ); + } + + if ( pw_buf.acct_ctrl == 0 ) { + pw_buf.acct_ctrl = ACB_NORMAL; + } + + pw_buf.pass_last_set_time = get_number( CHANGE_TIME(row) ); + + return (void*)&pw_buf; +} + +MYSQL_ROW *mysql_getpwent(void *vp) { + mysql_ctrl *mysql; + static MYSQL_ROW row; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + mysql = (mysql_ctrl*)vp; + row = mysql_fetch_row( mysql->result ); + + if ( row == NULL ) { + return NULL; + } + + mysql->current_row++; + + return &row; +} + +struct smb_passwd *mysql_getsmbpwent(void *vp) { + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + return (struct smb_passwd*)mysql_fill_smb_passwd( mysql_getpwent(vp) ); +} + +void *mysql_fetch_passwd( mysql_fill_func filler, char *where ) { + void *retval; + MYSQL handle; + MYSQL_RES *result; + MYSQL_ROW row; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + if ( filler == NULL ) { + return NULL; + } + + if ( where == NULL || *where == '\0' ) { + DEBUG(0,("Null or empty query\n")); + return NULL; + } + + if ( mysql_db_connect( &handle ) ) { + return NULL; + } + + result = mysql_select_results( &handle, where ); + if ( result == NULL ) { + mysql_close( &handle ); + return NULL; + } + + row = mysql_fetch_row ( result ); + if ( row == NULL ) { + mysql_free_result( result ); + mysql_close( &handle ); + return NULL; + } + + if ( DEBUGLEVEL >= 7 ) { + int field; + for (field=0; field< mysql_num_fields( result ); field++ ) { + DEBUG(7,(" row[%d] = \"%s\"\n",field,row[field]?row[field]:"NULL")); + } + } + + retval = (*filler)( &row ); + + mysql_free_result( result ); + mysql_close( &handle ); + + return retval; +} + +void *mysql_getpwuid(mysql_fill_func filler, uid_t uid) { + fstring where; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + slprintf( where, sizeof(where), "unix_uid=%lu", uid); + + return mysql_fetch_passwd(filler,where); +} + +struct smb_passwd *mysql_getsmbpwuid(uid_t uid) { + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + return (struct smb_passwd *)mysql_getpwuid( FILL_SMB, uid ); +} + +void *mysql_getpwnam(mysql_fill_func filler, char *field, const char *name) { + fstring where; + char format[] = "%s='%s'"; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + if ( filler == NULL ) { + DEBUG(0,("Empty fill opteration\n")); + return NULL; + } + + if ( field == NULL || *field == '\0' ) { + DEBUG(0,("Empty or NULL field name\n")); + return NULL; + } + + if ( name == NULL || *name == '\0' ) { + DEBUG(0,("Empty or NULL query\n")); + return NULL; + } + + if ( sizeof(format) + strlen(name) + strlen(field) > sizeof(where) ) { + DEBUG(0,("Query string too long\n")); + return NULL; + } + + slprintf(where, sizeof( where ), format, field, name ); + + return mysql_fetch_passwd( filler, where ); +} + +struct smb_passwd *mysql_getsmbpwnam(const char *unix_name) { + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + return mysql_getpwnam( FILL_SMB, "unix_name", unix_name ); +} + +static void quote_string(char *target, char *string) { + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + if ( string == NULL ) { + fstrcpy( target, "NULL" ); + } + else { + target[0] = '\''; + safe_strcpy(&target[1],string,sizeof(fstring)-2); + safe_strcpy(&target[strlen(target)],"'",2); + } +} + +BOOL mysql_del_smb( MYSQL *handle, char *unix_name ) { + pstring query; + char format[] = "delete from %s where unix_name='%s'"; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + if (strlen( format ) + strlen(mysql_table) + strlen(unix_name)) { + return False; + } + + slprintf( query, sizeof(query), format, mysql_table, unix_name); + + if ( mysql_query( handle, query ) ) { + DEBUG(0,("%s: %s\n", query, mysql_error(handle) )); + return False; + } + + return True; +} + +BOOL mysql_add_smb( MYSQL *handle, struct smb_passwd *smb ) { + pstring query; + char format[] = "insert into %s (unix_name, unix_uid) values ( '%s', %lu )"; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + if ( strlen(format) + strlen(mysql_table) + strlen(smb->unix_name) + 10 > sizeof(query) ) { + DEBUG(0,("Query too long\n")); + return False; + } + + slprintf( query, sizeof(query), "insert into %s (unix_name,unix_uid) values ('%s', %lu)", mysql_table, smb->unix_name, smb->unix_uid); + + if ( mysql_query( handle, query ) ) { + DEBUG(0,("%s: %s\n",query,mysql_error(handle) )); + return False; + } + + return True; +} + +BOOL mysql_mod_smb( MYSQL *handle, struct smb_passwd *smb, BOOL override ) { + pstring query; + fstring smb_passwd; + fstring smb_nt_passwd; + fstring nt_name; + + 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'"; + char extra[] = " and not ISNULL(smb_passwd)"; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + if ( strlen(format) + 2*20 + 3*10 + 2*32 + strlen(mysql_table) >= sizeof( query ) + strlen( extra ) ) { + DEBUG(0,("Query string too long\n")); + return False; + } + + quote_hash(smb_passwd, smb->smb_passwd); + quote_hash(smb_nt_passwd, smb->smb_nt_passwd); + + quote_string(nt_name, smb->nt_name); + + 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); + + if ( override != True ) { + pstrcat( query, extra ); + } + + if ( mysql_query( handle, query ) ) { + DEBUG(0,("%s: %s\n",query,mysql_error(handle) )); + return False; + } + + if ( mysql_affected_rows( handle ) < 1 ) { + DEBUG(3,("No entries changed\n")); + return False; + } + + return True; +} + +BOOL mysql_add_smbpwd_entry(struct smb_passwd *smb) { + MYSQL handle; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + if ( smb == NULL ) { + return False; + } + + if ( mysql_db_lock_connect( &handle ) ) { + return False; + } + + if ( !mysql_add_smb( &handle, smb ) ) { + mysql_close( &handle ); + return False; + } + + if ( !mysql_mod_smb( &handle, smb, True ) ) { + mysql_del_smb( &handle, smb->unix_name ); + mysql_close( &handle ); + return False; + } + + mysql_close(&handle); + return True; +} + +BOOL mysql_mod_smbpwd_entry(struct smb_passwd *smb, BOOL override) { + MYSQL handle; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + if ( smb == NULL ) { + return False; + } + + if ( mysql_db_lock_connect( &handle ) ) { + return False; + } + + if ( !mysql_mod_smb( &handle, smb, override ) ) { + mysql_close(&handle); + return False; + } + + mysql_close(&handle); + return True; +} + +static struct smb_passdb_ops mysql_ops = { + mysql_startpwent, + mysql_endpwent, + mysql_getpwpos, + mysql_setpwpos, + mysql_getsmbpwnam, + mysql_getsmbpwuid, + mysql_getsmbpwent, + mysql_add_smbpwd_entry, + mysql_mod_smbpwd_entry +}; + +struct smb_passdb_ops *mysql_initialise_password_db(void) +{ + (void*)mysql_retrieve_password(NULL); + return &mysql_ops; +} + +#else + void mysql_dummy_smb_function(void) { } +#endif diff --git a/source3/passdb/mysqlsampass.c b/source3/passdb/mysqlsampass.c new file mode 100644 index 0000000000..8d3049ce0a --- /dev/null +++ b/source3/passdb/mysqlsampass.c @@ -0,0 +1,265 @@ +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * Samba MYSQL SAM Database, by Benjamin Kuit. + * Copyright (C) Benjamin Kuit 1999, + * Copyright (C) Andrew Tridgell 1992-1999, + * Copyright (C) Luke Kenneth Casson Leighton 1996-1998, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef WITH_MYSQLSAM + +#include "includes.h" +#include <mysql.h> + +extern int DEBUGLEVEL; + +extern pstring samlogon_user; +extern BOOL sam_logon_in_ssb; + +typedef void *(*mysql_fill_func)( MYSQL_ROW * ); +#define FILL_SAM mysql_fill_sam_passwd + +void *mysql_startpwent(BOOL update); +void mysql_endpwent(void *vp); +SMB_BIG_UINT mysql_getpwpos(void *vp); +BOOL mysql_setpwpos(void *vp, SMB_BIG_UINT pos); +void *mysql_fill_smb_passwd( MYSQL_ROW *row ); +MYSQL_ROW *mysql_getpwent(void *vp); +void *mysql_fetch_passwd( mysql_fill_func filler, char *where ); +void *mysql_getpwuid( mysql_fill_func filler, uid_t uid ); +void *mysql_getpwnam( mysql_fill_func filler, char *field, const char *name ); +int mysql_db_lock_connect( MYSQL *handle ); +BOOL mysql_add_smb( MYSQL *handle, struct smb_passwd *smb ); +BOOL mysql_mod_smb( MYSQL *handle, struct smb_passwd *smb, BOOL override ); +BOOL mysql_del_smb( MYSQL *handle, char *unix_name ); + +void *mysql_fill_sam_passwd( MYSQL_ROW *row ) { + static struct sam_passwd *user; + + static pstring full_name; + static pstring home_dir; + static pstring home_drive; + static pstring logon_script; + static pstring profile_path; + static pstring acct_desc; + static pstring workstations; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + user = pwdb_smb_to_sam((struct smb_passwd *)mysql_fill_smb_passwd(row)); + + if ( user == NULL ) { + return NULL; + } + + /* 'Researched' from sampass.c =) */ + + pstrcpy(samlogon_user, user->unix_name); + + if (samlogon_user[strlen(samlogon_user)-1] == '$' && + user->group_rid != DOMAIN_GROUP_RID_USERS) + { + DEBUG(0,("trust account %s should be in DOMAIN_GROUP_RID_USERS\n", samlogon_user)); + } + + /* XXXX hack to get standard_sub_basic() to use sam logon username */ + /* possibly a better way would be to do a become_user() call */ + sam_logon_in_ssb = True; + + pstrcpy(full_name , ""); + pstrcpy(logon_script , lp_logon_script ()); + pstrcpy(profile_path , lp_logon_path ()); + pstrcpy(home_drive , lp_logon_drive ()); + pstrcpy(home_dir , lp_logon_home ()); + pstrcpy(acct_desc , ""); + pstrcpy(workstations , ""); + + sam_logon_in_ssb = False; + + user->full_name = full_name; + user->home_dir = home_dir; + user->dir_drive = home_drive; + user->logon_script = logon_script; + user->profile_path = profile_path; + user->acct_desc = acct_desc; + user->workstations = workstations; + + user->unknown_str = NULL; /* don't know, yet! */ + user->munged_dial = NULL; /* "munged" dial-back telephone number */ + + user->unknown_3 = 0xffffff; /* don't know */ + user->logon_divs = 168; /* hours per week */ + user->hours_len = 21; /* 21 times 8 bits = 168 */ + memset(user->hours, 0xff, user->hours_len); /* available at all hours */ + user->unknown_5 = 0x00020000; /* don't know */ + user->unknown_6 = 0x000004ec; /* don't know */ + + return (void*)user; +} + +struct sam_passwd *mysql_getsampwent(void *vp) { + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + return (struct sam_passwd*)mysql_fill_sam_passwd( mysql_getpwent(vp) ); +} + +struct sam_passwd *mysql_getsampwrid(uint32 rid) { + fstring where; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + slprintf( where, sizeof(where), "user_rid=%lu", (long unsigned)rid); + + return (struct sam_passwd *)mysql_fetch_passwd( FILL_SAM, where ); +} + +struct sam_passwd *mysql_getsampwuid(uid_t uid) { + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + return (struct sam_passwd *)mysql_getpwuid( FILL_SAM, uid ); +} + +struct sam_passwd *mysql_getsampwntnam(const char *nt_name) { + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + return (struct sam_passwd *)mysql_getpwnam( FILL_SAM, "nt_name", nt_name); +} + +struct sam_disp_info *mysql_getsamdispntnam(const char *nt_name) { + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + return pwdb_sam_to_dispinfo(mysql_getsampwntnam(nt_name)); +} + +struct sam_disp_info *mysql_getsamdisprid(uint32 rid) { + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + return pwdb_sam_to_dispinfo(mysql_getsampwrid(rid)); +} + +struct sam_disp_info *mysql_getsamdispent(void *vp) { + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + return pwdb_sam_to_dispinfo(mysql_getsampwent(vp)); +} + +static BOOL mysql_mod_sam( MYSQL *handle, struct sam_passwd *sam, BOOL override ) { + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + return True; +} + +BOOL mysql_add_sampwd_entry(struct sam_passwd *sam) { + MYSQL handle; + struct smb_passwd *smb; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + smb = pwdb_sam_to_smb( sam ); + + if ( smb == NULL ) { + return False; + } + + if ( mysql_db_lock_connect( &handle ) ) { + return False; + } + + if ( !mysql_add_smb( &handle, smb ) ) { + mysql_close(&handle); + return False; + } + + if ( !mysql_mod_smb( &handle, smb, True ) ) { + mysql_del_smb( &handle, smb->unix_name ); + mysql_close(&handle); + return False; + } + + if ( !mysql_mod_sam( &handle, sam, True ) ) { + mysql_del_smb( &handle, smb->unix_name ); + mysql_close(&handle); + return False; + } + + mysql_close(&handle); + return True; +} + +BOOL mysql_mod_sampwd_entry(struct sam_passwd *sam, BOOL override) { + MYSQL handle; + struct smb_passwd *smb; + + DEBUG(5,("%s\n",FUNCTION_MACRO)); + + smb = pwdb_sam_to_smb(sam); + + if ( smb == NULL ) { + return False; + } + + if ( mysql_db_lock_connect( &handle ) ) { + return False; + } + + if ( !mysql_mod_smb( &handle, smb, override ) ) { + mysql_close(&handle); + return False; + } + + if ( !mysql_mod_sam( &handle, sam, override ) ) { + mysql_close(&handle); + return False; + } + + mysql_close(&handle); + return True; +} + +static struct sam_passdb_ops sam_mysql_ops = +{ + mysql_startpwent, + mysql_endpwent, + mysql_getpwpos, + mysql_setpwpos, + mysql_getsampwntnam, + mysql_getsampwuid, + mysql_getsampwrid, + mysql_getsampwent, + mysql_add_sampwd_entry, + mysql_mod_sampwd_entry, + mysql_getsamdispntnam, + mysql_getsamdisprid, + mysql_getsamdispent +}; + +struct sam_passdb_ops *mysql_initialise_sam_password_db(void) +{ + return &sam_mysql_ops; +} + +#else + void mysql_dummy_sam_function(void) { } +#endif diff --git a/source3/passdb/passdb.c b/source3/passdb/passdb.c index b80ab625ed..9936dd2293 100644 --- a/source3/passdb/passdb.c +++ b/source3/passdb/passdb.c @@ -70,6 +70,8 @@ BOOL initialise_password_db(void) pwdb_ops = nisplus_initialise_password_db(); #elif defined(WITH_LDAP) pwdb_ops = ldap_initialise_password_db(); +#elif defined(WITH_MYSQL) || defined(WITH_MYSQLSAM) + pwdb_ops = mysql_initialise_password_db(); #elif defined(USE_SMBPASS_DB) pwdb_ops = file_initialise_password_db(); #endif diff --git a/source3/passdb/sampassdb.c b/source3/passdb/sampassdb.c index 45fc07daf8..a4c981b160 100644 --- a/source3/passdb/sampassdb.c +++ b/source3/passdb/sampassdb.c @@ -70,6 +70,8 @@ BOOL initialise_sam_password_db(void) pwdb_ops = nisplus_initialise_sam_password_db(); #elif defined(WITH_LDAP) pwdb_ops = ldap_initialise_sam_password_db(); +#elif defined(WITH_MYSQLSAM) + pwdb_ops = mysql_initialise_sam_password_db(); #elif defined(USE_SMBPASS_DB) pwdb_ops = file_initialise_sam_password_db(); #endif diff --git a/source3/script/mysql_convert.pl b/source3/script/mysql_convert.pl new file mode 100644 index 0000000000..e9c1b9de56 --- /dev/null +++ b/source3/script/mysql_convert.pl @@ -0,0 +1,364 @@ +#!/usr/local/bin/perl + +use Mysql; + +$ACB_DISABLED=0x0001; +$ACB_HOMDIRREQ=0x0002; +$ACB_PWNOTREQ=0x0004; +$ACB_TEMPDUP=0x0008; +$ACB_NORMAL=0x0010; +$ACB_MNS=0x0020; +$ACB_DOMTRUST=0x0040; +$ACB_WSTRUST=0x0080; +$ACB_SVRTRUST=0x0100; +$ACB_PWNOEXP=0x0200; +$ACB_AUTOLOCK=0x0400; + +sub getoptionval { + my ($option) = @_; + + my ($value) = ($option =~ /^[^=]+=\s*(\S.*\S)/ ); + + return $value; +} + +sub usage { + +print <<EOUSAGE; +$0 [options] +options: + --infile=<filename> # smbpasswd style file to read entries from + --outfile=<filename> # file to dump results to, format depending + # on --infile: + # With --infile: Dump mysql script queries + # Without --infile: Dump smbpasswd format + # from reading mysql database + --host=<hostname> # Mysql Server name (default: localhost) + --db=<database> # Mysql Database name + --user=<user> # Mysql User + --password[=<password>] # Mysql password for --user + --table=<table> # Mysql table + --create # Generate 'create table' query + --file=[trash|append] # Action to take if --outfile file exists + --check # Do not alter or skip bad uids + +EOUSAGE +exit 0; +} + +sub getpass { + my($prompt)=@_; + my($ret); + + print $prompt; + system "stty -echo"; + chomp($ret=<STDIN>); + system "stty echo"; + print "\n"; + $ret; +} + +sub next_entry { + my ($name,$uid,$lm,$nt,$f,$lct) = (); + + $name=""; + if ( not $infile ) { + ($name,$uid,$lm,$nt,$f,$lct) = $mysqlquery->fetchrow(); + } + else { + my $line=<INFILE>; + + return () if ( not $line ); + + chomp($line); + + next if ( $line !~ /^[^: ]+:\d+:/ ); + + ($name,$uid,$lm,$nt,$f,$lct) = split(/:/,$line); + + if ( $lct =~ /^LCT-/ ) { + # New Format smbpasswd file + my $flags=0; + + $flags |= $ACB_PWNOTREQ if ( $f =~ /N/ ); + $flags |= $ACB_DISABLED if ( $f =~ /D/ ); + $flags |= $ACB_HOMDIRREQ if ( $f =~ /H/ ); + $flags |= $ACB_TEMPDUP if ( $f =~ /T/ ); + $flags |= $ACB_NORMAL if ( $f =~ /U/ ); + $flags |= $ACB_MNS if ( $f =~ /M/ ); + $flags |= $ACB_WSTRUST if ( $f =~ /W/ ); + $flags |= $ACB_SVRTRUST if ( $f =~ /S/ ); + $flags |= $ACB_AUTOLOCK if ( $f =~ /L/ ); + $flags |= $ACB_PWNOEXP if ( $f =~ /X/ ); + $flags |= $ACB_DOMTRUST if ( $f =~ /I/ ); + + $f = $flags; + + $f = $ACB_NORMAL if ( not $f ); + + $lct =~ s/LCT-//; + $lct = (unpack("L",pack("H8",$lct)))[0]; + } + else { + # Old Format smbpasswd file + $f = 0; + $lct = time(); + if ( $lm =~ /^NO PASS/ ) { + $f |= $ACB_PWNOTREQ; + $lm = ""; + $nt = ""; + } + elsif ( $lm =~ /^XX/ ) { + $f |= $ACB_DISABLED; + + $lm = ""; + $nt = ""; + } + + if ( $name =~ /\$$/ ) { + $f |= $ACB_WSTRUST; + } + + $f = $ACB_NORMAL if ( not $f ); + } + } + return () if ( not $name ); + ($name,$uid,$lm,$nt,$f,$lct); +} + +sub do_query { + my ( $query ) = @_; + + chomp($query); + if ( $outfile ) { + print OUTFILE "$query;\n"; + } + else { + if ( not $mysqldb->query($query) ) { + print "$query: $Mysql::db_errstr\n"; + } + } +} + +sub do_file { + my ($file,$name,$uid,$lm,$nt,$f,$lct)=@_; + + my $strings = ""; + + $strings .= "N" if ( $f & $ACB_PWNOTREQ ); + $strings .= "D" if ( $f & $ACB_DISABLED ); + $strings .= "H" if ( $f & $ACB_HOMDIRREQ ); + $strings .= "T" if ( $f & $ACB_TEMPDUP ); + $strings .= "U" if ( $f & $ACB_NORMAL ); + $strings .= "M" if ( $f & $ACB_MNS ); + $strings .= "W" if ( $f & $ACB_WSTRUST ); + $strings .= "S" if ( $f & $ACB_SVRTRUST ); + $strings .= "L" if ( $f & $ACB_AUTOLOCK ); + $strings .= "X" if ( $f & $ACB_PWNOEXP ); + $strings .= "I" if ( $f & $ACB_DOMTRUST ); + + $f = sprintf( "[%-11s]", $strings ); + + $lct=uc("LCT-".(unpack("H8",pack("L","$lct")))[0]); + + $lm = "X"x32 if ( not $lm ); + $nt = "X"x32 if ( not $nt ); + + print $file "$name:$uid:$lm:$nt:$f:$lct\n"; +} + +$dbhost = "localhost"; + +for $option ( @ARGV ) { + if ( $option =~ /--outfile=/ ) { + $outfile = getoptionval($option); + } + elsif ( $option =~ /--infile=/ ) { + $infile = getoptionval($option); + } + elsif ( $option =~ /--db=/ ) { + $dbname = getoptionval($option); + } + elsif ( $option =~ /--user=/ ) { + $dbuser = getoptionval($option); + } + elsif ( $option =~ /--host=/ ) { + $dbhost = getoptionval($option); + } + elsif ( $option =~ /--password/ ) { + $dbpasswd = getoptionval($option); + $need_password = "yes" + } + elsif ( $option =~ /--table=/ ) { + $dbtable = getoptionval($option); + } + elsif ( $option =~ /--create/ ) { + $create_table = "yes"; + } + elsif ( $option =~ /--file=/ ) { + $file_action = getoptionval($option); + } + elsif ( $option =~ /--check/ ) { + $check = "yes"; + } + else { + print "Unknown option: $option\n"; + $unknown = "yes"; + } +} + +&usage if ( $unknown eq "yes" ); + +if ( ( not $infile ) && ( not $outfile ) && ( $create_table ne "yes" ) ) { + print "Need file to read from or write to\n"; + &usage; +} +elsif ( $infile && $outfile ) { + if ( not $dbtable ) { + print "Need --table to create queries\n"; + exit 1; + } + + # Reading a smbpasswd file, dumping queries into an file which + # can be used for a mysql script + # --db* options are ignored. + + $ignored = ""; + $ignored .= " --db" if ( $dbname ); + $ignored .= " --user" if ( $dbuser ); + $ignored .= " --password" if ( $dbuser ); + + if ( $ignored ) { + print "Ignoring options: $ignored\n"; + } +} +elsif ( (not $dbname) || (not $dbtable) || (not $dbuser) ) { + print "Missing database particulars:\n"; + print " --db=??\n" if ( not $dbname ); + print " --user=??\n" if ( not $dbuser ); + print " --table=??\n" if ( not $dbtable ); + &usage; +} +else { + if ( ($need_password eq "yes") && ( not $dbpasswd )) { + $dbpasswd = getpass("Enter MySQL password for $dbuser: "); + } + $mysqldb = Connect Mysql($dbhost,$dbname,$dbuser,$dbpasswd); + + if ( not $mysqldb ) { + print "Cannot connect to database: $Mysql::db_errstr\n"; + exit 1; + } + + if ( $outfile ) { + $mysqlquery = $mysqldb->query("select unix_name,unix_uid,smb_passwd,smb_nt_passwd,acct_ctrl,pass_last_set_time from $dbtable"); + + if ( not $mysqlquery ) { + print "MySQL Query failed: $Mysql::db_errstr\n"; + exit 1; + } + } +} + +if ( $create_table eq "yes" ) { + $create_table_query=<<EOSQL; +create table $dbtable ( +unix_name char(20) not null, +unix_uid int(10) unsigned not null, +nt_name char(20) not null, +user_rid int(10) unsigned not null, +smb_passwd char(32), +smb_nt_passwd char(32), +acct_ctrl int(10) unsigned not null, +pass_last_set_time int(10) unsigned not null, +unique (unix_name), +unique (unix_uid) +) +EOSQL + print "$create_table_query\n"; +} +if ( $infile ) { + if ( not open(INFILE,$infile) ) { + print "$infile: $!\n"; + exit 1; + } +} + +if ( $outfile ) { + if ( ! -f $outfile ) { + $open_string=">$outfile"; + } + elsif ( not $file_action ) { + print "File $outfile exists:\n"; + print "Please use --file=[trash|append] option to determine destiny of file\n"; + exit 1; + } + elsif ( $file_action eq "append" ) { + $open_string = ">>$outfile"; + } + else { + $open_string = ">$outfile"; + } + + if ( not open(OUTFILE,$open_string) ) { + print "$outfile: $!\n"; + exit 1; + } +} + +do_query($create_table_query) if ( $create_table_query ); + +$linenum=1; +while (($name,$uid,$lm,$nt,$f,$lct)=next_entry()) { + + $| = 1; + print "\r$linenum "; + $linenum++; + + $nuid = ""; + + $nuid = (getpwnam(lc($name)))[2]; + + if ( $check ) { + if ( not $nuid ) { + # print "Removing $name: Does not exist\n"; + push(@removed,[$name,$uid,$lm,$nt,$f,$lct]); + next; + } + else { + # print "Changing uid of $name\n"; + $uid = $nuid; + } + } + + if ( $infile ) { + if ( $lm ) { + $lm = "'$lm'"; + } + else { + $lm = "NULL"; + } + if ( $nt ) { + $nt = "'$nt'"; + } + else { + $nt = "NULL"; + } + $rid=(4*$uid)+1000; + do_query("insert into $dbtable (unix_name,unix_uid,smb_passwd,smb_nt_passwd,acct_ctrl,pass_last_set_time,nt_name,user_rid) values ('$name',$uid,$lm,$nt,$f,$lct,'$name',$rid)"); + } + else { + do_file(OUTFILE,$name,$uid,$lm,$nt,$f,$lct); + } +} + +if ( @removed ) { + print "\n\nIgnored entries because usernames do not exist\n"; + foreach $line ( @removed ) { + do_file(STDOUT,@{ $line }); + } +} + +close (OUTFILE) if ( $outfile ); +close (INFILE) if ( $infile ); +print "\n"; |