📄 mal_authorize.c
字号:
#line 83 "/export/scratch0/monet/monet.GNU.64.64.d.14791/MonetDB5/src/mal/mal_authorize.mx"#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);}#line 160 "/export/scratch0/monet/monet.GNU.64.64.d.14791/MonetDB5/src/mal/mal_authorize.mx"voidAUTHcommit() { 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 * old password must match the one stored before the new password is * set. */strAUTHchangePassword(str *oldpass, str *passwd) { BUN p; str tmp; str hash; oid id; /* precondition checks */ if (*oldpass == NULL || strNil(*oldpass)) throw(ILLARG, "changePassword", "old password should not be nil"); if (*passwd == NULL || strNil(*passwd)) throw(ILLARG, "changePassword", "password should not be nil"); /* check the old password */ id = MCgetClient()->user; p = BUNfnd(pass, &id); assert(p != NULL); tmp = BUNtail(pass, p); assert (tmp != NULL); if (strcmp(tmp, *oldpass) != 0) throw(INVCRED, "changePassword", "Access denied"); /* cypher the password */ rethrow("setPassword", tmp, AUTHcypherValue(&hash, passwd)); /* ok, just overwrite the password field for this user */ BUNinplace(pass, p, BUNhead(pass, p), &hash, FALSE); AUTHcommit(); return(MAL_SUCCEED);}/** * Changes the password of the given user to the given password. This * function can be used by the administrator to reset the password for a * user. Note that for the administrator to change its own password, it * cannot use this function for obvious reasons. */strAUTHsetPassword(str *username, str *passwd) { BUN p; str tmp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -