/* Copyright (C) 1999 Beau Kuiper 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, 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. */ #include "config.h" #include "auth.h" #include #include #include #include /* This file contains code to autheticate against mysql servers */ #define ENCRYPTED_NONE 0 #define ENCRYPTED_MYSQL 1 #define ENCRYPTED_CRYPT 2 typedef struct { char *password; char *homedir; char *rootdir; int uid; int gid; int encrypted; } PASSWDSTRUCT; void *gethandle(void *peer, void *tset, char *username, int *err) { MYSQL *sql = NULL; MYSQL_RES *result = NULL; MYSQL_ROW row = NULL; PASSWDSTRUCT *newhandle; int section; char *sqlserver; char *sqlencryption; char *sqlusername; char *sqlpassword; char *sqldatabase; int sqlport; char *sqltable; char *sqlquery, *query = NULL; section = auth_getcursectionid(peer); newhandle = (PASSWDSTRUCT *)mallocwrapper(sizeof(PASSWDSTRUCT)); /* read info from config file */ sqlserver = mktokconfstr(tset, section, "mysql_host", "localhost"); sqlusername = mktokconfstr(tset, section, "mysql_user", NULL); sqlpassword = mktokconfstr(tset, section, "mysql_password", NULL); sqldatabase = mktokconfstr(tset, section, "mysql_database", NULL); sqltable = mktokconfstr(tset, section, "mysql_table", "users"); sqlport = mktokconfint(tset, section, "mysql_port", "%d", NULL, 0); sqlencryption = mktokconfstr(tset, section, "mysql_encryption", "mysql"); sqlquery = mktokconfstr(tset, section, "mysql_query", NULL); if (!sqlusername) { log_addentry(MYLOG_INFO, NULL, "libauthmysql REQUIRES mysql_user to connect to sql server"); goto error; } if (!sqlpassword) { log_addentry(MYLOG_INFO, NULL, "libauthmysql REQUIRES mysql_password to connect to sql server"); goto error; } if (!sqldatabase) { log_addentry(MYLOG_INFO, NULL, "libauthmysql REQUIRES mysql_database to connect to sql server"); goto error; } if (strcasecmp(sqlencryption, "mysql") == 0) newhandle->encrypted = ENCRYPTED_MYSQL; else if (strcasecmp(sqlencryption, "plaintext") == 0) newhandle->encrypted = ENCRYPTED_NONE; else if (strcasecmp(sqlencryption, "crypt") == 0) newhandle->encrypted = ENCRYPTED_CRYPT; else { log_addentry(MYLOG_INFO, NULL, "libauthmysql REQUIRES mysql_encryption to be set to either plaintext, mysql, crypt"); goto error; } if (!sqlquery) query = safe_snprintf("SELECT password,homedir,rootdir,uid,gid FROM %s WHERE username='%s'", sqltable, username); else query = strdupwrapper(sqlquery); /* connect to sql server */ sql = mysql_init(NULL); if (!mysql_real_connect(sql, sqlserver, sqlusername, sqlpassword, sqldatabase, sqlport, NULL, 0)) { log_giveentry(MYLOG_INFO, NULL, safe_snprintf("libauthmysql could not connect to SQL server: %s", mysql_error(sql))); goto error; } /* perform sql query */ if (mysql_query(sql, query) != 0) { log_giveentry(MYLOG_INFO, NULL, safe_snprintf("libauthmysql could not perform query on SQL server: %s", mysql_error(sql))); goto error; } if (mysql_field_count(sql) != 5) { log_addentry(MYLOG_INFO, NULL, "libauthmysql, mysql_query setting incorrectly set"); goto error; } /* get result data */ if ((result = mysql_store_result(sql)) == NULL) { log_giveentry(MYLOG_INFO, NULL, safe_snprintf("libauthmysql could not get results from SQL query: %s", mysql_error(sql))); goto error; } /* if we got no rows, then the user does not exist */ if (mysql_num_rows(result) == 0) { freewrapper(newhandle); newhandle = NULL; *err = AUTH_USERNKNOW; goto cleanup; } if (mysql_num_rows(result) > 1) { log_giveentry(MYLOG_INFO, NULL, safe_snprintf("libauthmysql got more than 1 result for query on user '%s'", username)); goto error; } /* decode row */ row = mysql_fetch_row(result); if (!row[0] || !row[1] || !row[2] || !row[3] || !row[4]) { log_giveentry(MYLOG_INFO, NULL, safe_snprintf("libauthmysql found NULL values in SQL result for user '%s'", username)); goto error; } if (sscanf(row[3], "%d", &(newhandle->uid)) != 1) { log_giveentry(MYLOG_INFO, NULL, safe_snprintf("libauthmysql could not decode uid of user '%s'", username)); goto error; } if (sscanf(row[4], "%d", &(newhandle->gid)) != 1) { log_giveentry(MYLOG_INFO, NULL, safe_snprintf("libauthmysql could not decode gid of user '%s'", username)); goto error; } newhandle->password = strdupwrapper(row[0]); newhandle->homedir = strdupwrapper(row[1]); newhandle->rootdir = strdupwrapper(row[2]); /* we are FINALLY DONE!, clean up and go home! */ *err = AUTH_OK; goto cleanup; error: *err = AUTH_ERROR; freewrapper(newhandle); newhandle = NULL; cleanup: if (query) freewrapper(query); if (result) mysql_free_result(result); if (sql) mysql_close(sql); freewrapper(sqlserver); if (sqlusername) freewrapper(sqlusername); if (sqlpassword) freewrapper(sqlpassword); if (sqldatabase) freewrapper(sqldatabase); freewrapper(sqltable); freewrapper(sqlencryption); if (sqlquery) freewrapper(sqlquery); return(newhandle); } void freehandle(void *handle) { PASSWDSTRUCT *h = (PASSWDSTRUCT *)handle; size_t sl = strlen(h->password); /* destroy record of password */ memset(h->password, 0, sl); freewrapper(h->password); freewrapper(h->homedir); freewrapper(h->rootdir); freewrapper(h); } int chkpasswd(void *handle, char *password, char **errmsg) { PASSWDSTRUCT *h = (PASSWDSTRUCT *)handle; char pass2[1024]; switch(h->encrypted) { case ENCRYPTED_NONE: return(strcmp(password, h->password) == 0); case ENCRYPTED_CRYPT: return(chkpassword(h->password, password)); case ENCRYPTED_MYSQL: make_scrambled_password(pass2, password); return(strcmp(h->password, pass2) == 0); default: return(FALSE); } return(FALSE); } char *gethomedir(void *h) { return(((PASSWDSTRUCT *)h)->homedir); } char *getrootdir(void *h) { return(((PASSWDSTRUCT *)h)->rootdir); } uid_t getuseruid(void *h) { return(((PASSWDSTRUCT *)h)->uid); } gid_t getusergid(void *h) { return(((PASSWDSTRUCT *)h)->gid); }