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

📄 mal_authorize.c

📁 一个内存数据库的源代码这是服务器端还有客户端
💻 C
📖 第 1 页 / 共 2 页
字号:
	str hash;	oid id;	rethrow("setPassword", tmp, AUTHrequireAdmin());	/* precondition checks */	if (*username == NULL || strNil(*username))		throw(ILLARG, "setPassword", "username should not be nil");	if (*passwd == NULL || strNil(*passwd))		throw(ILLARG, "setPassword", "password should not be nil");	id = MCgetClient()->user;	/* find the name of the administrator and see if it equals username */	p = BUNfnd(user, &id);	assert (p != NULL);	tmp = BUNtail(user, p);	assert (tmp != NULL);	if (strcmp(tmp, *username) == 0)		throw(INVCRED, "setPassword", "The administrator cannot set its own password, use changePassword instead");	/* see if the user is valid */	p = BUNfnd(BATmirror(user), *username);	if (p == NULL)		throw(MAL, "setPassword", "no such user '%s'", *username);	id = *(oid*)BUNhead(user, p);	/* cypher the password */	rethrow("setPassword", tmp, AUTHcypherValue(&hash, passwd));	/* ok, just overwrite the password field for this user */	p = BUNfnd(pass, &id);	assert (p != NULL);	BUNinplace(pass, p, BUNhead(pass, p), &hash, FALSE);	AUTHcommit();	return(MAL_SUCCEED);}/** * Adds the given scenario to the list of allowed scenarios for the * given user.  Note that this can result in unexpected behaviour when * there where previously no scenarios defined for the user (which means * all scenarios are permitted). */strAUTHaddScenario(str *username, str *scenario) {	BUN p;	str tmp;	oid *id;	BAT *b;	rethrow("addScenario", tmp, AUTHrequireAdmin());	/* precondition checks */	if (*username == NULL || strNil(*username))		throw(ILLARG, "addScenario", "username should not be nil");	if (*scenario == NULL || strNil(*scenario))		throw(ILLARG, "addScenario", "scenario should not be nil");	/* see if the user is valid */	p = BUNfnd(BATmirror(user), *username);	if (p == NULL)		throw(MAL, "addScenario", "user '%s' does not exist", *username);	id = (oid*)BUNhead(user, p);	/* see if this scenario is not already there */	b = BATselect(BATmirror(scen), id, id);	b = BATselect(BATmirror(b), *scenario, *scenario);	if (BATcount(b) == 1)		throw(MAL, "addScenario", "scenario '%s' already exists for user '%s'", *scenario, *username);	if (BATcount(b) > 1)		throw(MAL, "addScenario", "inconsistent authorisation administration, scenario '%s' multiple times defined", *scenario);	/* add the scenario for this user, use force as sql makes view over it */	BUNins(scen, BUNhead(user, p), *scenario, TRUE);	AUTHcommit();	return(MAL_SUCCEED);}/** * Removes the given scenario from the list of allowed scenarios for the * given user.  Note that removing the last allowed scenario results in * the opposite effect: it will allow any scenario to be used. */strAUTHremoveScenario(str *username, str *scenario) {	BUN p;	BAT *b;	oid *id;	str tmp;	rethrow("removeScenario", tmp, AUTHrequireAdmin());	/* precondition checks */	if (*username == NULL || strNil(*username))		throw(ILLARG, "removeScenario", "username should not be nil");	if (*scenario == NULL || strNil(*scenario))		throw(ILLARG, "removeScenario", "scenario should not be nil");	/* see if the user is valid */	p = BUNfnd(BATmirror(user), *username);	if (p == NULL)		throw(MAL, "removeScenario", "user '%s' does not exist", *username);	id = (oid*)BUNhead(user, p);	/* see if the scenario is valid for this user */	b = BATselect(BATmirror(scen), id, id);	b = BATselect(BATmirror(b), *scenario, *scenario);	if (BATcount(b) == 0)		throw(MAL, "removeScenario", "scenario '%s' not found for user '%s'", *scenario, *username);	if (BATcount(b) > 1)		throw(MAL, "removeScenario", "inconsistent authorisation administration, scenario '%s' multiple times defined", *scenario);	/* ok, remove it */	BATdel(scen, BATmirror(b), TRUE);	AUTHcommit();	return(MAL_SUCCEED);}/** * Resolves the given user id and returns the associated username.  If * the id is invalid, an exception is thrown.  The given pointer to the * username char buffer should be NULL if this function is supposed to * allocate memory for it.  If the pointer is pointing to an already * allocated buffer, it is supposed to be of size BUFSIZ. */strAUTHresolveUser(str *username, oid *uid) {	BUN p;	if (uid == NULL || *uid == oid_nil)		throw(ILLARG, "resolveUser", "userid should not be nil");		p = BUNfnd(user, uid);	if (p == NULL)		throw(MAL, "resolveUser", "No such user with id: " OIDFMT, *uid);	assert (username != NULL);	if (*username == NULL) {		*username = GDKstrdup((str)(BUNtail(user, p)));	} else {		snprintf(*username, BUFSIZ, "%s", (str)(BUNtail(user, p)));	}	return(MAL_SUCCEED);}/** * Returns the username of the current user. */strAUTHgetUsername(str *username) {	BUN p;	oid id;	id = MCgetClient()->user;	p = BUNfnd(user, &id);	if (p == NULL) {		GDKfatal("Internal error: user id that doesn't exist: " OIDFMT,				MCgetClient()->user);	}	*username = BUNtail(user, p);	return(MAL_SUCCEED);}/** * Returns a BAT with user names in the tail, and user ids in the head. * Only those users are returned that have access to all of the given * scenarios. */strAUTHgetUsers(bat *ret, bat *scenarios) {	BAT *b, *r;	str tmp;	rethrow("getUsers", tmp, AUTHrequireAdmin());	if (*scenarios != bat_nil) {		b = BATdescriptor(*scenarios);		if (b == NULL)			throw(ILLARG, "getUsers", "invalid BAT!");		if (b->htype != TYPE_str)			throw(ILLARG, "getUsers", "BAT should have str head");		if (BATcount(b) == 0) {			/* we can simply copy the whole users table, as there is no			 * selection */			r = BATcopy(user, user->htype, user->ttype, FALSE);		} else {			BAT *t1;			BAT *t2;						/* we have to do some work in order to return the requested			 * rows; only those that have the given scenario(s) (all of			 * them) */			/* all users with no scenarios are always in the return			 * list, we find them by "inversing" the list of users			 * *with* a scenario */			t1 = BATkdiff(user, BATkunique(scen));						/* find users with one or more scenarios in the given BAT */			t2 = BATjoin(					VIEWcombine(BATkunique(BATjoin(scen, b, BATcount(scen)))),					user,					BATcount(user)				);			/* the final result is the union of both (we can discard the			 * tail, as they *should* be equal when the heads are equal			 * too... */			r = BATkunion(t1, t2);		}		BBPunfix(*scenarios);	} else {		r = BATcopy(user, user->htype, user->ttype, FALSE);		BBPunfix(*scenarios);	}	*ret = BBPcacheid(r);	return(NULL);}/*=== the vault ===*//* yep, the vault key is just stored in memory */static str vaultKey = NULL;/** * Unlocks the vault with the given password.  Since the password is * just the decypher key, it is not possible to directly check whether * the given password is correct.  If incorrect, however, all decypher * operations will probably fail or return an incorrect decyphered * value. */strAUTHunlockVault(str *password) {	str tmp;	rethrow("unlockVault", tmp, AUTHrequireAdmin());	if (password == NULL || strNil(*password))		throw(ILLARG, "unlockVault", "password should not be nil");	/* even though I think this function should be called only once, it	 * is not of real extra efforts to avoid a mem-leak if it is used	 * multiple times	 */	if (vaultKey != NULL)		GDKfree(vaultKey);	vaultKey = GDKstrdup(*password);	return(MAL_SUCCEED);}/** * Decyphers a given value, using the vaultKey.  The returned value * might be incorrect if the vaultKey is incorrect or unset.  If the * cypher algorithm fails or detects an invalid password, it might throw * an exception.  The ret string is GDKmalloced, and should be GDKfreed * by the caller. */static strAUTHdecypherValue(str *ret, str *value) {	/* Cyphering and decyphering can be done using many algorithms.	 * Future requirements might want a stronger cypher than the XOR	 * cypher chosen here.  It is left up to the implementor how to do	 * that once those algoritms become available.  It could be	 * #ifdef-ed or on if-basis depending on whether the cypher	 * algorithm is a compile, or runtime option.  When necessary, this	 * function could be extended with an extra argument that indicates	 * the cypher algorithm.	 */		/* this is the XOR decypher implementation */	str r = GDKmalloc(sizeof(char) * (strlen(*value) + 1));	str w = r;	str s = *value;	int escaped = 0;	/* we default to some garbage key, just to make password unreadable	 * (a space would only uppercase the password) */	int keylen = 0;	if (vaultKey == NULL)		throw(MAL, "decypherValue", "The vault is still locked!");	keylen = strlen(vaultKey);	/* XOR all characters.  If we encounter a 'one' char after the XOR	 * operation, it is an escape, so replace it with the next char. */	for (; *s != '\0'; s++) {		if (*s == '\1' && escaped == 0) {			escaped = 1;			continue;		} else if (escaped != 0) {			*s -= 1;			escaped = 0;		}		*w = *s ^ vaultKey[(w - r) % keylen];		w++;	}	*w = '\0';	*ret = r;	return(MAL_SUCCEED);}/** * Cyphers the given string using the vaultKey.  If the cypher algorithm * fails or detects an invalid password, it might throw an exception. * The ret string is GDKmalloced, and should be GDKfreed by the caller. */static strAUTHcypherValue(str *ret, str *value) {	/* this is the XOR cypher implementation */	str r = GDKmalloc(sizeof(char) * (strlen(*value) * 2 + 1));	str w = r;	str s = *value;	/* we default to some garbage key, just to make password unreadable	 * (a space would only uppercase the password) */	int keylen = 0;	if (vaultKey == NULL)		throw(MAL, "decypherValue", "The vault is still locked!");	keylen = strlen(vaultKey);	/* XOR all characters.  If we encounter a 'zero' char after the XOR	 * operation, escape it with an 'one' char. */	for (; *s != '\0'; s++) {		*w = *s ^ vaultKey[(s - *value) % keylen];		if (*w == '\0') {			*w++ = '\1';			*w = '\1';		} else if (*w == '\1') {			*w++ = '\1';			*w = '\2';		}		w++;	}	*w = '\0';	*ret = r;	return(MAL_SUCCEED);}/** * Returns a comma separated list of supported hash algorithms.  The * returned string is GDKmalloced and should be GDKfreed. */strAUTHgetHashAlgorithms(str *ret) {	/* currently, four "hashes" are available, SHA-1, MD5, crypt and	 * plain.  Both "sha1" and "md5" are supported if OpenSSL is	 * available at compile time.  The same holds for "crypt", the UNIX	 * crypt implementation.  The last option, "plain" is not a hash at	 * all, but always available as it requires no modifications to the	 * password, i.e. it is send over in plain text.	 */	str t = alloca(sizeof(char) * BUFSIZ);	*t = '\0';#ifdef HAVE_OPENSSL	strcat(t, "SHA1,MD5,");#endif#ifdef HAVE_CRYPT	strcat(t, "crypt,");#endif	strcat(t, "plain");	*ret = GDKstrdup(t);	return(MAL_SUCCEED);}/** * Returns the hash for the given password, challenge and algorithm. * The hash calculated using the given algorithm over the password * concatenated with the challenge. */static strAUTHhashPassword(str *ret, str *algo, str *password, str *challenge) {	if (strcmp(*algo, "plain") == 0) {		/* The plain text algorithm, doesn't really hash at all.  It's		 * the easiest algorithm, as it just appends the challenge to		 * the password and returns it.		 */		*ret = GDKmalloc(sizeof(char) * (strlen(*password) + strlen(*challenge) + 1));		sprintf(*ret, "%s%s", *password, *challenge);		return(MAL_SUCCEED);#ifdef HAVE_OPENSSL	} else if (strcmp(*algo, "SHA1") == 0) {		/* The SHA-1 RSA hash algorithm is a 160 bit hash.  In order to		 * use in a string, a hexadecimal representation of the bit		 * sequence is used.		 */		unsigned char md[20]; /* should be SHA_DIGEST_LENGTH */		int len = strlen(*password) + strlen(*challenge);		char key[len];		strcpy(key, *password);		strncat(key, *challenge, strlen(*challenge));		SHA1((unsigned char*)key, len, md);		*ret = GDKmalloc(sizeof(char) * (20 * 2 + 1));		sprintf(*ret, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"				"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",				md[0], md[1], md[2], md[3], md[4],				md[5], md[6], md[7], md[8], md[9],				md[10], md[11], md[12], md[13], md[14],				md[15], md[16], md[17], md[18], md[19]			);		return(MAL_SUCCEED);	} else if (strcmp(*algo, "MD5") == 0) {		/* The MD5 hash algorithm is a 128 bit hash.  In order to		 * use in a string, a hexadecimal representation of the bit		 * sequence is used.		 */		unsigned char md[16]; /* should be MD5_DIGEST_LENGTH */		int len = strlen(*password) + strlen(*challenge);		char key[len];		strcpy(key, *password);		strncat(key, *challenge, strlen(*challenge));		MD5((unsigned char*)key, len, md);		*ret = GDKmalloc(sizeof(char) * (16 * 2 + 1));		sprintf(*ret, "%02x%02x%02x%02x%02x%02x%02x%02x"				"%02x%02x%02x%02x%02x%02x%02x%02x",				md[0], md[1], md[2], md[3],				md[4], md[5], md[6], md[7],				md[8], md[9], md[10], md[11],				md[12], md[13], md[14], md[15]			);		return(MAL_SUCCEED);#endif#ifdef HAVE_CRYPT	} else if (strcmp(*algo, "crypt") == 0) {		/* The crypt hash algorithm uses UNIX crypt, a modification of		 * DES which uses a 2-char wide salt.  Because crypt only cares		 * about the first eight characters of the given password, the		 * challenge may not be taken into account at all.  As salt, the		 * last two characters of the challenge are used.		 */		char key[8]; /* NULL termination is not necessary */		char salt[3]; /* NULL termination is a necessity! */		str hash;		int len;		/* prepare the key */		len = strlen(*password);		if (len >= 8) {			strncpy(key, *password, 8);		} else {			/* pad with the challenge, we know it is always 8+ chars */			strncpy(key, *password, len);			strncpy(key + len, *challenge, 8 - len);		}		/* prepare the salt */		len = strlen(*challenge);		salt[0] = *challenge[len - 2];		salt[1] = *challenge[len - 1];		salt[2] = '\0';		/* call crypt to do the work */		hash = crypt(key, salt);		assert (hash != NULL);		*ret = GDKstrdup(hash);		return(MAL_SUCCEED);#endif	} else {		throw(MAL, "hashPassword", "unsupported hash type: '%s'", algo);	}}#line 1038 "/export/scratch0/monet/monet.GNU.64.64.d.14791/MonetDB5/src/mal/mal_authorize.mx"

⌨️ 快捷键说明

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