⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mal_authorize.mx

📁 一个内存数据库的源代码这是服务器端还有客户端
💻 MX
📖 第 1 页 / 共 2 页
字号:
@' The contents of this file are subject to the MonetDB Public License@' Version 1.1 (the "License"); you may not use this file except in@' compliance with the License. You may obtain a copy of the License at@' http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html@'@' Software distributed under the License is distributed on an "AS IS"@' basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the@' License for the specific language governing rights and limitations@' under the License.@'@' The Original Code is the MonetDB Database System.@'@' The Initial Developer of the Original Code is CWI.@' Portions created by CWI are Copyright (C) 1997-2007 CWI.@' All Rights Reserved.@f mal_authorize@a M. Kersten, F. Groffen@v 0.2@+ Authorisation adminstration managementAuthorisation of users is a key concept in protecting the server frommalicious and unauthorised users.  This file contains a number offunctions that administrate a set of BATs backing the authorisationtables.The implementation is based on three persistent BATs, which keep theusernames, passwords and allowed scenarios for users of the server.@h#ifndef _MAL_AUTHORIZE_H#define _MAL_AUTHORIZE_H/* #define _DEBUG_AUTH_*/#include "mal.h"#include "mal_exception.h"#include "mal_instruction.h"#include "mal_client.h"mal_export str AUTHcheckCredentials(oid *ret, str *user, str *passwd, str *challenge, str *algo, str *scenario);mal_export str AUTHcheckUser(int *ret, str *user, str *passwd);mal_export str AUTHaddUser(oid *ret, str *user, str *pass, bat *scenarios);mal_export str AUTHremoveUser(str *username);mal_export str AUTHchangeUsername(str *olduser, str *newuser);mal_export str AUTHchangePassword(str *oldpass, str *passwd);mal_export str AUTHsetPassword(str *username, str *passwd);mal_export str AUTHaddScenario(str *username, str *scenario);mal_export str AUTHremoveScenario(str *username, str *scenario);mal_export str AUTHresolveUser(str *ret, oid *uid);mal_export str AUTHgetUsername(str *ret);mal_export str AUTHgetUsers(bat *ret, bat *scenarios);mal_export str AUTHrequireAdmin(void);mal_export str AUTHrequirteAdminOrUser(str *username);mal_export str AUTHinitTables(void);@-Authorisation is based on a password.  The passwords are stored cypheredin a BAT.  Access to this BAT should be prohibited from the MAL level,but still, the passwords in it are to be stored cyphered with analgorithm that has a decypher.  The database administrator can unlockthe BAT that stores the password (the vault) by supplying the masterpassword which is the key for the cypher algorithm.  The BAT will nevercontain decyphered passwords, as they will be decyphered on the fly whenneeded.  A locked vault means noone can log into the system, hence, thevault needs to be unlocked as part of the server startup ritual.@hmal_export str AUTHunlockVault(str *password);@-To avoid the passwords from being sent over the wire in plain textformat, MAPI starts with sending a challenge with salt.  This saltshould be appended to the plain text password before it is hashed inorder to make the password unreadable for eavesdroppers.  The hashalgorithm used is specified by the client, and can be chosen from acomma separated list offered by the server through the challenge(protocol >=6).@hmal_export str AUTHgetHashAlgorithms(str *ret);#endif /* _MAL_AUTHORIZE_H */@-@c#include "mal_config.h"#include "mal_authorize.h"#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef HAVE_CRYPT_H#include <crypt.h>#else#if defined(HAVE_CRYPT) && defined(__MINGW32__)_CRTIMP char * __cdecl crypt(const char *key, const char *salt);#endif#endif#ifdef HAVE_OPENSSL#include <openssl/sha.h>#include <openssl/md5.h>#endifstatic str AUTHdecypherValue(str *ret, str *value);static str AUTHcypherValue(str *ret, str *value);static str AUTHhashPassword(str *ret, str *algo, str *passwd, str *challenge);static BAT *user = NULL;static BAT *pass = NULL;static BAT *scen = NULL;/** * Requires the current client to be the admin user.  If not the case, * this function returns an InvalidCredentialsException. */strAUTHrequireAdmin() {	oid id = MCgetClient()->user;	if (id != 0) {		char u[BUFSIZ]="";		str user = u;		str tmp;				rethrow("requireAdmin", tmp, AUTHresolveUser(&user, &id));		throw(INVCRED, "requireAdmin", "Access denied for user '%s'", user);	}	return(MAL_SUCCEED);}/** * Requires the current client to be the admin user, or the user with * the given username.  If not the case, this function returns an * InvalidCredentialsException. */strAUTHrequireAdminOrUser(str *username) {	oid id = MCgetClient()->user;	char u[BUFSIZ]= "";	str user = u;	str tmp= MAL_SUCCEED;	/* root?  then all is well */	if (id == 0) return(MAL_SUCCEED);	rethrow("requireAdminOrUser", tmp, AUTHresolveUser(&user, &id));	if (username == NULL || *username == NULL || strcmp(*username, user) != 0) {		throw(INVCRED, "requireAdminOrUser", "Access denied for user '%s'", user);	}	return(MAL_SUCCEED);}@-Localize the authorization tables in the database.  The authorizationtables are a set of aligned BATs that store username, password (hashed)and scenario permissions.If the BATs do not exist, they are created, and the monetdb/monetdbadministrator account is added.  Initialising the authorization tablescan only be done after the GDK kernel has been initialized.@cvoidAUTHcommit() {	BAT *b = BATnew(TYPE_oid, TYPE_str, 3);	assert(b);	assert(user);	BUNappend(b, BATgetId(user), FALSE);	assert(pass);	BUNappend(b, BATgetId(pass), FALSE);	assert(pass);	BUNappend(b, BATgetId(scen), FALSE);	TMsubcommit(b);	BBPreclaim(b);}strAUTHinitTables() {	bat bid;	BAT *b;	int isNew = 1;	/* skip loading if already loaded */	if (user != NULL && pass != NULL && scen != NULL)		return(MAL_SUCCEED);	/* if one is not NULL here, something is seriously screwed up */	assert (user == NULL);	assert (pass == NULL);	assert (scen == NULL);	/* load/create users BAT */	bid = BBPindex("M5system_auth_user");	if (!bid) {		b = BATnew(TYPE_oid, TYPE_str, 256);		if (b == NULL)			throw(MAL, "initTables", "could not allocate user table");		BATkey(BATmirror(b), TRUE);		BBPrename(BBPcacheid(b), "M5system_auth_user");		BATmode(b, PERSISTENT);	} else {		b = BATdescriptor(bid);		isNew = 0;	}		assert(b);	user = b;	/* load/create password BAT */	bid = BBPindex("M5system_auth_passwd");	if (!bid) {		b = BATnew(TYPE_oid, TYPE_str, 256);		if (b == NULL)			throw(MAL, "initTables", "could not allocate password table");		BBPrename(BBPcacheid(b), "M5system_auth_passwd");		BATmode(b, PERSISTENT);	} else {		b = BATdescriptor(bid);		isNew = 0;	}	assert(b);	pass = b;	/* load/create scenario BAT */	bid = BBPindex("M5system_auth_scen");	if (!bid) {		b = BATnew(TYPE_oid, TYPE_str, 256);		if (b == NULL)			throw(MAL, "initTables", "could not allocate scenario table");		BATkey(b, TRUE);		BBPrename(BBPcacheid(b), "M5system_auth_scen");		BATmode(b, PERSISTENT);	} else {		b = BATdescriptor(bid);		isNew = 0;	}	assert(b);	scen = b;	if (isNew == 1) {		/* insert the monetdb/monetdb administrator account on a		 * complete fresh and new auth tables system */		str user = "monetdb";		str pass = "monetdb";		bat b = bat_nil;		str tmp;		oid uid;		rethrow("initTables", tmp, AUTHaddUser(&uid, &user, &pass, &b));		if (uid != 0)			throw(MAL, "initTables", "authorisation BATs not empty, but they were just created !?!?!?");		AUTHcommit();	}	return(MAL_SUCCEED);}/** * Check if the user/password combination aligns with * a given uid.*/strAUTHcheckUser(	int *ret,	str *username,	str *passwd){	/* to be filled */	(void) username; (void) passwd;	*ret =1;	return MAL_SUCCEED;}/** * Checks the credentials supplied and throws an exception if invalid. * The user id of the authenticated user is returned upon success. */strAUTHcheckCredentials(		oid *uid,		str *username,		str *passwd,		str *challenge,		str *algo,		str *scenario){	str tmp;	str pwd;	str hash;	BAT *b;	BUN p, q;	oid *id;	rethrow("checkCredentials", tmp, AUTHrequireAdminOrUser(username));	assert(user);	assert(pass);	assert(scen);	if (*username == NULL || strNil(*username))		throw(INVCRED, "checkCredentials", "Invalid credentials for unknown user");	p = BUNfnd(BATmirror(user), *username);	if (p == NULL) {		/* DO NOT reveal that the user doesn't exist here! */		throw(INVCRED, "checkCredentials", "Invalid credentials for user '%s'",				*username);	}	id = (oid*)(BUNhead(user, p));	/* a NULL password is impossible (since we should be dealing with	 * hashes here) so we can bail out immediately	 */	if (*passwd == NULL || strNil(*passwd)) {		/* DO NOT reveal that the password is NULL here! */		throw(INVCRED, "checkCredentials", "Invalid credentials for user '%s'",				*username);	}	/* find the corresponding password to the user */	q = BUNfnd(pass, id);	assert (q != NULL);	tmp = (str)BUNtail(pass, q);	assert (tmp != NULL);	/* decypher the password (we lose the original tmp here) */	rethrow("checkCredentials", tmp, AUTHdecypherValue(&pwd, &tmp));	/* generate the hash as the client should have done */	rethrow("checkCredentials", tmp, AUTHhashPassword(&hash, algo, &pwd, challenge));	/* and now we have it, compare it to what was given to us */	if (strcmp(*passwd, hash) != 0) {		/* of course we DO NOT print the password here */		throw(INVCRED, "checkCredentials", "Invalid credentials for user '%s'",				*username);	}	/* now see if the scenario is permitted (if restrictions for that	 * apply)	 */	b = BATselect(scen, id, id);	if (b && BATcount(b) > 0) {		if (*scenario == NULL || strNil(*scenario)) {			/* of course we DO NOT tell the exact reason here again */			throw(INVCRED, "checkCredentials", "Invalid credentials for user '%s'",					*username);		}		/* ok, there are some tuples that we have to consider */		BATloop(b, p, q) {			tmp = (str)BUNtail(b, p);			assert (tmp != NULL);			if (strcmp(*scenario, tmp) == 0) {				/* YAY!  fun!  party!  We are granted access! */				*uid = *id;				return(MAL_SUCCEED);			}		}		/* uh oh... that we made it till here means it's wrong */		throw(INVCRED, "checkCredentials", "Invalid credentials for user '%s'",				*username);	} else {		/* no scenario restriction applies, so everything is good */		*uid = *id;		return(MAL_SUCCEED);	}}/** * Adds the given user with password to the administration.  The scens * BAT contains all scenarios allowed for the user.  If NULL or empty, * no restrictions for a scenario applies.  The return value of this * function is the user id of the added user. */strAUTHaddUser(oid *uid, str *username, str *passwd, bat *scenarios) {	BUN p, q;	BAT *b;	oid *id;	str tmp;	str hash;	rethrow("addUser", tmp, AUTHrequireAdmin());	assert(user);	assert(pass);	assert(scen);		/* some pre-condition checks */	if (*username == NULL || strNil(*username))		throw(ILLARG, "addUser", "username cannot be nil");	if (*passwd == NULL || strNil(*passwd))		throw(ILLARG, "addUser", "password cannot be nil");	/* ensure that the username is not already there */	p = BUNfnd(BATmirror(user), *username);	if (p != NULL)		throw(MAL, "addUser", "user '%s' already exists", *username);		/* we assume the BATs are still aligned */	rethrow("addUser", tmp, AUTHcypherValue(&hash, passwd));	/* needs force, as SQL makes a view over user */	BUNappend(user, *username, TRUE);	BUNappend(pass, hash, FALSE);	/* should always be private! */	/* retrieve the oid of the just inserted user */	p = BUNfnd(BATmirror(user), *username);	assert (p != NULL);	id = (oid*)(BUNhead(user, p));	if (*scenarios != bat_nil) {		b = BATdescriptor(*scenarios);		if (b == NULL) {			BATundo(user);			BATundo(pass);			throw(ILLARG, "addUser", "invalid BAT!");		}		if (b->htype != TYPE_str) {			BATundo(user);			BATundo(pass);			throw(ILLARG, "addUser", "BAT should have str head");		}		/* associate scenarios given in the BAT with the user */		if (BATcount(b) > 0) {			BATloop(b, p, q) {				/* needs force, as sql makes a view over it */				BUNins(scen, id, BUNhead(b, p), TRUE);			}		}	}	/* make the stuff persistent */	AUTHcommit();	*uid = *id;	return(MAL_SUCCEED);}/** * Removes the given user from the administration.  All scenarios (if * any) and the password are removed as well. */strAUTHremoveUser(str *username) {	BUN p;	BAT *b;	oid id;	str tmp;	rethrow("removeUser", tmp, AUTHrequireAdmin());	assert(user);	assert(pass);	assert(scen);	/* pre-condition check */	if (*username == NULL || strNil(*username))		throw(ILLARG, "removeUser", "username cannot be nil");	/* ensure that the username exists */	p = BUNfnd(BATmirror(user), *username);	if (p == NULL)		throw(MAL, "removeUser", "no such user: '%s'", *username);	id = *(oid*)(BUNhead(user, p));	/* find the name of the administrator and see if it equals username */	if (id == MCgetClient()->user)		throw(MAL, "removeUser", "cannot remove yourself");	/* now, we got the oid, start removing the related tuples */	b = BATmirror(BATselect(BATmirror(user), &id, &id));	assert(BATcount(b) != 0);	BATdel(user, b, TRUE);	b = BATmirror(BATselect(BATmirror(pass), &id, &id));	assert(BATcount(b) != 0);	BATdel(pass, b, FALSE);	b = BATmirror(BATselect(BATmirror(scen), &id, &id));	BATdel(scen, b, TRUE);	/* make the stuff persistent */	AUTHcommit();	return(MAL_SUCCEED);}/** * Changes the username of the user indicated by olduser into newuser. * If the username is already in use, an exception is thrown and nothing * is modified. */strAUTHchangeUsername(str *olduser, str *newuser) {	BUN p, q;	str tmp;	rethrow("addUser", tmp, AUTHrequireAdminOrUser(olduser));	/* precondition checks */	if (*olduser == NULL || strNil(*olduser))		throw(ILLARG, "changeUsername", "old username should not be nil");	if (*newuser == NULL || strNil(*newuser))		throw(ILLARG, "changeUsername", "new username should not be nil");	/* see if the olduser is valid */	p = BUNfnd(BATmirror(user), *olduser);	if (p == NULL)		throw(MAL, "changeUsername", "user '%s' does not exist", *olduser);	/* ... and if the newuser is not there yet */	q = BUNfnd(BATmirror(user), *newuser);	if (q != NULL)		throw(MAL, "changeUsername", "user '%s' already exists", *newuser);	/* ok, just do it! (with force, because sql makes view over it) */	BUNinplace(BATmirror(user), p, *newuser, BUNhead(user, p), TRUE);	AUTHcommit();	return(MAL_SUCCEED);}/** * Changes the password of the current user to the given password.  The

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -