summaryrefslogblamecommitdiffstats
path: root/cpukit/httpd/um.c
blob: 58e288affbc20f3dd46739f2d7c82c05d8d927f1 (plain) (tree)






















































                                                                                    






                                                                             



































































                                                                             
  

                                                  
                                   
 
  











                                                                                             
                                                                 

   
                
























                                                                                
                                                                 

   
                  

































                                                                                
                                                                    





















                                                                                
                                                                      










                                                                                
                                      





                                                           
                               












                                                                              
                                                


































                                                                                                
                                                                        


                          
                                                                      










                                                                                
                                                                       


                                                                                  
                                                                      














                                                                                
                                                                        











                                                                             
                                                                              













                                                                                
                                                            





















































                                                                            
                                                                 




















                                                                                
         





                                                                                   
         









                                                                                  
                            






                                                                                
                                                       































































































































































































































                                                                                       
                                                              





                                                        
 























































                                                                                
         





                                                     
         










































                                                                                    
         





                                                                               
         









                                                                                
                             























































































                                                                                       
                                                                               







































                                                                                 
                                                                             







































                                                                                
                                                                          











































































                                                                                   
                                   





                                                                                
                                                                               





































                                                                                                    
         























































                                                                                        
                                                                             























































                                                                                    
 

















                                                                        
                                                                               




                                                       
                                                                              





















                                                                                
 



























                                                                                
 























































                                                                                
                                                        



                                 

         
  
                                                                      


                              









                                                                           

                                                                    
 
                 
      
         

  
                                          

                    
 












                                                                                
                                                             












                                                                                
/*
 *	um.c -- User Management
 *
 *	Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
 *
 *	See the file "license.txt" for usage and redistribution license requirements
 *
 *	$Id$
 */

/******************************** Description *********************************/
/*
 *	User Management routines for adding/deleting/changing users and groups
 *  Also, routines for determining user access
 */

/********************************* Includes ***********************************/

#include	"um.h"
#include	"emfdb.h"
#include	"webs.h"

/********************************** Defines ***********************************/

#define UM_DB_FILENAME	T("um.xml")
#define UM_TXT_FILENAME	T("umconfig.txt")

/*
 *	Table names
 */
#define UM_USER_TABLENAME	T("users")
#define UM_GROUP_TABLENAME	T("groups")
#define UM_ACCESS_TABLENAME	T("access")

/*
 *	Column names
 */
#define UM_NAME			T("name")
#define UM_PASS			T("password")
#define UM_GROUP		T("group")
#define UM_PROT			T("prot")
#define UM_DISABLE		T("disable")
#define UM_METHOD		T("method")
#define UM_PRIVILEGE	T("priv")
#define UM_SECURE		T("secure")

/*
 *	XOR encryption mask
 *		Note:	This string should be modified for individual sites
 *				in order to enhance user password security.
 */
#define UM_XOR_ENCRYPT	T("*j7a(L#yZ98sSd5HfSgGjMj8;Ss;d)(*&^#@$a2s0i3g")

/******************************** Local Data **********************************/

#ifdef qHierarchicalAccess
/*
 * user-provided function to allow hierarchical access protection. See below.
 * for details.
 */
extern bool_t dmfCanAccess(const char_t* usergroup, const char_t* group);
#endif
#ifdef UEMF
/*
 *	User table definition
 */
#define NUMBER_OF_USER_COLUMNS	5

char_t	*userColumnNames[NUMBER_OF_USER_COLUMNS] = {
			UM_NAME, UM_PASS, UM_GROUP, UM_PROT, UM_DISABLE
};

int		userColumnTypes[NUMBER_OF_USER_COLUMNS] = {
			T_STRING, T_STRING, T_STRING, T_INT, T_INT
};

dbTable_t userTable = {
	UM_USER_TABLENAME,
	NUMBER_OF_USER_COLUMNS,
	userColumnNames,
	userColumnTypes,
	0,
	NULL
};

/*
 *	Group table definition
 */
#define NUMBER_OF_GROUP_COLUMNS	5

char_t	*groupColumnNames[NUMBER_OF_GROUP_COLUMNS] = {
			UM_NAME, UM_PRIVILEGE, UM_METHOD, UM_PROT, UM_DISABLE
};

int		groupColumnTypes[NUMBER_OF_GROUP_COLUMNS] = {
			T_STRING, T_INT, T_INT, T_INT, T_INT
};

dbTable_t groupTable = {
	UM_GROUP_TABLENAME,
	NUMBER_OF_GROUP_COLUMNS,
	groupColumnNames,
	groupColumnTypes,
	0,
	NULL
};

/*
 *	Access Limit table definition
 */
#define NUMBER_OF_ACCESS_COLUMNS	4

char_t	*accessColumnNames[NUMBER_OF_ACCESS_COLUMNS] = {
			UM_NAME, UM_METHOD, UM_SECURE, UM_GROUP
};

int		accessColumnTypes[NUMBER_OF_ACCESS_COLUMNS] = {
			T_STRING, T_INT, T_INT, T_STRING
};

dbTable_t accessTable = {
	UM_ACCESS_TABLENAME,
	NUMBER_OF_ACCESS_COLUMNS,
	accessColumnNames,
	accessColumnTypes,
	0,
	NULL
};
#endif	/* #ifdef UEMF */

/*
 *	Database Identifier returned from dbOpen()
 */
static int		didUM = -1;

/*
 *	Configuration database persist filename
 */
static char_t	*saveFilename = NULL;

static int		umOpenCount = 0;		/* count of apps using this module */

/*************************** Forward Declarations *****************************/

static bool_t umCheckName(char_t *name);

/*********************************** Code *************************************/
/*
 *	umOpen() registers the UM tables in the fake emf-database
 */

int umOpen(void)
{
	if (++umOpenCount != 1) {
		return didUM;
	}
/*
 *	Do not initialize if intialization has already taken place
 */
	if (didUM == -1) {
		didUM = dbOpen(UM_USER_TABLENAME, UM_DB_FILENAME, NULL, 0);
#ifdef UEMF
		dbRegisterDBSchema(&userTable);
		dbRegisterDBSchema(&groupTable);
		dbRegisterDBSchema(&accessTable);
#endif
	}

	if (saveFilename == NULL) {
		saveFilename = bstrdup(B_L, UM_TXT_FILENAME);
	}

	return didUM;
}

/******************************************************************************/
/*
 *	umClose() frees up the UM tables in the fake emf-database
 */

void umClose(void)
{
	if (--umOpenCount > 0) {
		return;
	}
/*
 *	Do not close if intialization has not taken place
 */
	if (didUM != -1) {
		dbClose(didUM);
		didUM = -1;
	}

	if (saveFilename != NULL) {
		bfree(B_L, saveFilename);
		saveFilename = NULL;
	}
}

/******************************************************************************/
/*
 *	umCommit() persists all of the UM tables
 */

int	umCommit(char_t *filename)
{
	if (filename && *filename) {
		if (saveFilename != NULL) {
			bfree(B_L, saveFilename);
		}

		saveFilename = bstrdup(B_L, filename);
	}

	a_assert (saveFilename && *saveFilename);
	trace(3, T("UM: Writing User Configuration to file <%s>\n"),
		saveFilename);

	return dbSave(didUM, saveFilename, 0);
}

/******************************************************************************/
/*
 *	umRestore() loads up the UM tables with persisted data
 */

int umRestore(char_t *filename)
{
	if (filename && *filename) {
		if (saveFilename != NULL) {
			bfree(B_L, saveFilename);
		}

		saveFilename = bstrdup(B_L, filename);
	}

	a_assert(saveFilename && *saveFilename);

	trace(3, T("UM: Loading User Configuration from file <%s>\n"),
		saveFilename);

/*
 *	First empty the database, otherwise we wind up with duplicates!
 */
	dbZero(didUM);
	return dbLoad(didUM, saveFilename, 0);
}

/******************************************************************************/
/*
 *	Encrypt/Decrypt a text string.
 *		Returns the number of characters encrypted.
 */

static int umEncryptString(char_t *textString)
{
	char_t	*enMask;
	unsigned char	enChar;
	int		numChars;

	a_assert(textString);

	enMask = UM_XOR_ENCRYPT;
	numChars = 0;

	while (*textString) {
		enChar = *textString ^ *enMask;
/*
 *		Do not produce encrypted text with embedded linefeeds or tabs.
 *			Simply use existing character.
 */
		if (enChar && !gisspace(enChar))
			*textString = enChar;
/*
 *		Increment all pointers.
 */
		enMask++;
		textString++;
		numChars++;
/*
 *		Wrap encryption mask pointer if at end of length.
 */
		if (*enMask == '\0') {
			enMask = UM_XOR_ENCRYPT;
		}
	}

	return numChars;
}

/******************************************************************************/
/*
 *	umGetFirstRowData() -	return a pointer to the first non-blank key value
 *							in the given column for the given table.
 */

static char_t *umGetFirstRowData(char_t *tableName, char_t *columnName)
{
	char_t	*columnData;
	int		row;
	int		check;

	a_assert(tableName && *tableName);
	a_assert(columnName && *columnName);

	row = 0;
/*
 *	Move through table until we retrieve the first row with non-null
 *	column data.
 */
	columnData = NULL;
	while ((check = dbReadStr(didUM, tableName, columnName, row++,
		&columnData)) == 0 || (check == DB_ERR_ROW_DELETED)) {
		if (columnData && *columnData) {
			return columnData;
		}
	}

	return NULL;
}

/******************************************************************************/
/*
 *	umGetNextRowData() -	return a pointer to the first non-blank
 *						key value following the given one.
 */

static char_t *umGetNextRowData(char_t *tableName, char_t *columnName,
								char_t *keyLast)
{
	char_t	*key;
	int		row;
	int		check;

	a_assert(tableName && *tableName);
	a_assert(columnName && *columnName);
	a_assert(keyLast && *keyLast);
/*
 *	Position row counter to row where the given key value was found
 */
	row = 0;
	key = NULL;

	while ((((check = dbReadStr(didUM, tableName, columnName, row++,
		&key)) == 0) || (check == DB_ERR_ROW_DELETED)) &&
		((key == NULL) || (gstrcmp(key, keyLast) != 0))) {
	}
/*
 *	If the last key value was not found, return NULL
 */
	if (!key || gstrcmp(key, keyLast) != 0) {
		return NULL;
	}
/*
 *	Move through table until we retrieve the next row with a non-null key
 */
	while (((check = dbReadStr(didUM, tableName, columnName, row++, &key))
		== 0) || (check == DB_ERR_ROW_DELETED)) {
		if (key && *key && (gstrcmp(key, keyLast) != 0)) {
			return key;
		}
	}

	return NULL;
}

/******************************************************************************/
/*
 *	umAddUser() - Adds a user to the "users" table.
 */

int	umAddUser(char_t *user, char_t *pass, char_t *group,
			  bool_t prot, bool_t disabled)
{
	int		row;
	char_t	*password;

	a_assert(user && *user);
	a_assert(pass && *pass);
	a_assert(group && *group);

	trace(3, T("UM: Adding User <%s>\n"), user);

/*
 *	Do not allow duplicates
 */
	if (umUserExists(user)) {
		return UM_ERR_DUPLICATE;
	}

/*
 *	Make sure user name and password contain valid characters
 */
	if (!umCheckName(user)) {
		return UM_ERR_BAD_NAME;
	}

	if (!umCheckName(pass)) {
		return UM_ERR_BAD_PASSWORD;
	}

/*
 *	Make sure group exists
 */
	if (!umGroupExists(group)) {
		return UM_ERR_NOT_FOUND;
	}

/*
 *	Now create the user record
 */
	row = dbAddRow(didUM, UM_USER_TABLENAME);

	if (row < 0) {
		return UM_ERR_GENERAL;
	}

	if (dbWriteStr(didUM, UM_USER_TABLENAME, UM_NAME, row, user) != 0) {
		return UM_ERR_GENERAL;
	}

	password = bstrdup(B_L, pass);
	umEncryptString(password);
	dbWriteStr(didUM, UM_USER_TABLENAME, UM_PASS, row, password);
	bfree(B_L, password);
	dbWriteStr(didUM, UM_USER_TABLENAME, UM_GROUP, row, group);
	dbWriteInt(didUM, UM_USER_TABLENAME, UM_PROT, row, prot);
	dbWriteInt(didUM, UM_USER_TABLENAME, UM_DISABLE, row, disabled);

	return 0;
}

/******************************************************************************/
/*
 *	umDeleteUser() - remove a user from the "users" table
 */

int	umDeleteUser(char_t *user)
{
	int row;

	a_assert(user && *user);
	trace(3, T("UM: Deleting User <%s>\n"), user);
/*
 *	Check to see if user is delete-protected
 */
	if (umGetUserProtected(user)) {
		return UM_ERR_PROTECTED;
	}

/*
 *	If found, delete the user from the database
 */
	if ((row = dbSearchStr(didUM, UM_USER_TABLENAME, UM_NAME, user, 0)) >= 0) {
		return dbDeleteRow(didUM, UM_USER_TABLENAME, row);
	}

	return UM_ERR_NOT_FOUND;
}

/******************************************************************************/
/*
 *	umGetFirstUser() -	Returns the user ID of the first user found in the
 *						"users" table.
 */

char_t *umGetFirstUser(void)
{
	return umGetFirstRowData(UM_USER_TABLENAME, UM_NAME);
}

/******************************************************************************/
/*
 *	umGetNextUser()	Returns the next user found in the "users" table after
 *					the given user.
 */

char_t *umGetNextUser(char_t *userLast)
{
	return umGetNextRowData(UM_USER_TABLENAME, UM_NAME, userLast);
}

/******************************************************************************/
/*
 *	umUserExists()	Returns TRUE if userid exists.
 */

bool_t umUserExists(char_t *user)
{
	a_assert(user && *user);

	if (dbSearchStr(didUM, UM_USER_TABLENAME, UM_NAME, user, 0) >= 0) {
		return TRUE;
	} else {
		return FALSE;
	}
}

/******************************************************************************/
/*
 *	umGetUserPassword() returns a de-crypted copy of the user password
 */

char_t *umGetUserPassword(char_t *user)
{
	char_t	*password;
	int		row;

	a_assert(user && *user);

	password = NULL;
	row = dbSearchStr(didUM, UM_USER_TABLENAME, UM_NAME, user, 0);

	if (row >= 0) {
		char_t *pass = NULL;
		dbReadStr(didUM, UM_USER_TABLENAME, UM_PASS, row, &pass);
/*
 *		Decrypt	password
 *		Note, this function returns a copy of the password, which must
 *		be deleted at some time in the future.
 */
		password = bstrdup(B_L, pass);
		umEncryptString(password);
	}

	return password;
}

/******************************************************************************/
/*
 *	umSetUserPassword() updates the user password in the user "table" after
 *						encrypting the given password
 */

int	umSetUserPassword(char_t *user, char_t *pass)
{
	int		row, nRet;
	char_t	*password;

	a_assert(user && *user);
	a_assert(pass && *pass);
	trace(3, T("UM: Attempting to change the password for user <%s>\n"), user);
/*
 *	Find the row of the user
 */
	if ((row = dbSearchStr(didUM, UM_USER_TABLENAME, UM_NAME, user, 0)) < 0) {
		return UM_ERR_NOT_FOUND;
	}

	password = bstrdup(B_L, pass);
	umEncryptString(password);
	nRet = dbWriteStr(didUM, UM_USER_TABLENAME, UM_PASS, row, password);
	bfree(B_L, password);

	return nRet;
}

/******************************************************************************/
/*
 *	umGetUserGroup() returns the name of the user group
 */

char_t *umGetUserGroup(char_t *user)
{
	char_t	*group;
	int		row;

	a_assert(user && *user);
	group = NULL;
/*
 *	Find the row of the user
 */
	row = dbSearchStr(didUM, UM_USER_TABLENAME, UM_NAME, user, 0);

	if (row >= 0) {
		dbReadStr(didUM, UM_USER_TABLENAME, UM_GROUP, row, &group);
	}

	return group;
}

/******************************************************************************/
/*
 *	umSetUserGroup() Sets the name of the user group for the user
 */

int	umSetUserGroup(char_t *user, char_t *group)
{
	int row;

	a_assert(user && *user);
	a_assert(group && *group);
/*
 *	Find the row of the user
 */
	row = dbSearchStr(didUM, UM_USER_TABLENAME, UM_NAME, user, 0);

	if (row >= 0) {
		return dbWriteStr(didUM, UM_USER_TABLENAME, UM_GROUP, row, group);
	} else {
		return UM_ERR_NOT_FOUND;
	}
}

/******************************************************************************/
/*
 *	umGetUserEnabled() - returns if the user is enabled
 *	Returns FALSE if the user is not found.
 */

bool_t	umGetUserEnabled(char_t *user)
{
	int disabled, row;

	a_assert(user && *user);

	disabled = 1;
/*
 *	Find the row of the user
 */
	row = dbSearchStr(didUM, UM_USER_TABLENAME, UM_NAME, user, 0);

	if (row >= 0) {
		dbReadInt(didUM, UM_USER_TABLENAME, UM_DISABLE, row, &disabled);
	}

	return (bool_t)!disabled;
}

/******************************************************************************/
/*
 *	umSetUserEnabled() Enables/disables the user
 */
int	umSetUserEnabled(char_t *user, bool_t enabled)
{
	int row;

	a_assert(user && *user);
/*
 *	Find the row of the user
 */
	row = dbSearchStr(didUM, UM_USER_TABLENAME, UM_NAME, user, 0);
	if (row >= 0) {
		return dbWriteInt(didUM, UM_USER_TABLENAME, UM_DISABLE, row, !enabled);
	} else {
		return UM_ERR_NOT_FOUND;
	}
}

/******************************************************************************/
/*
 *	umGetUserProtected() - determine deletability of user
 */

bool_t umGetUserProtected(char_t *user)
{
	int protect, row;

	a_assert(user && *user);
/*
 *	Find the row of the user
 */
	row = dbSearchStr(didUM, UM_USER_TABLENAME, UM_NAME, user, 0);
	protect = FALSE;

	if (row >= 0) {
		dbReadInt(didUM, UM_USER_TABLENAME, UM_PROT, row, &protect);
	}

	return (bool_t)protect;
}

/******************************************************************************/
/*
 *	umSetUserProtected() sets the delete protection for the user
 */
int	umSetUserProtected(char_t *user, bool_t protect)
{
	int row;

	a_assert(user && *user);
/*
 *	Find the row of the user
 */
	row = dbSearchStr(didUM, UM_USER_TABLENAME, UM_NAME, user, 0);

	if (row >= 0) {
		return dbWriteInt(didUM, UM_USER_TABLENAME, UM_PROT, row, protect);
	} else {
		return UM_ERR_NOT_FOUND;
	}
}


/******************************************************************************/
/*
 *	umAddGroup() adds a group to the "Group" table
 */

int	umAddGroup(char_t *group, short priv, accessMeth_t am,
			   bool_t prot, bool_t disabled)
{
	int row;

	a_assert(group && *group);
	trace(3, T("UM: Adding group <%s>\n"), group);

/*
 *	Do not allow duplicates
 */
	if (umGroupExists(group)) {
		return UM_ERR_DUPLICATE;
	}

/*
 *	Only allow valid characters in key field
 */
	if (!umCheckName(group)) {
		return UM_ERR_BAD_NAME;
	}

/*
 *	Add a new row to the table
 */
	if ((row = dbAddRow(didUM, UM_GROUP_TABLENAME)) < 0) {
		return UM_ERR_GENERAL;
	}

/*
 *	Write the key field
 */
	if (dbWriteStr(didUM, UM_GROUP_TABLENAME, UM_NAME, row, group) != 0) {
		return UM_ERR_GENERAL;
	}

/*
 *	Write the remaining fields
 */
	dbWriteInt(didUM, UM_GROUP_TABLENAME, UM_PRIVILEGE, row, priv);
	dbWriteInt(didUM, UM_GROUP_TABLENAME, UM_METHOD, row, (int) am);
	dbWriteInt(didUM, UM_GROUP_TABLENAME, UM_PROT, row, prot);
	dbWriteInt(didUM, UM_GROUP_TABLENAME, UM_DISABLE, row, disabled);

	return 0;
}

/******************************************************************************/
/*
 *	umDeleteGroup() - Delete a user group, if not protected
 */

int	umDeleteGroup(char_t *group)
{
	int row;

	a_assert(group && *group);
	trace(3, T("UM: Deleting Group <%s>\n"), group);

/*
 *	Check to see if the group is in use
 */
	if (umGetGroupInUse(group)) {
		return UM_ERR_IN_USE;
	}

/*
 *	Check to see if the group is delete-protected
 */
	if (umGetGroupProtected(group)) {
		return UM_ERR_PROTECTED;
	}

/*
 *	Find the row of the group to delete
 */
	if ((row = dbSearchStr(didUM, UM_GROUP_TABLENAME, UM_NAME, group, 0)) < 0) {
		return UM_ERR_NOT_FOUND;
	}

	return dbDeleteRow(didUM, UM_GROUP_TABLENAME, row);
}

/******************************************************************************/
/*
 *	umGroupExists() returns TRUE if group exists, FALSE otherwise
 */

bool_t umGroupExists(char_t *group)
{
	a_assert(group && *group);

	if (dbSearchStr(didUM, UM_GROUP_TABLENAME, UM_NAME, group, 0) >= 0) {
		return TRUE;
	} else {
		return FALSE;
	}
}


/******************************************************************************/
/*
 *	umGetGroupInUse() returns TRUE if the group is referenced by a user or by
 *  an access limit.
 */

bool_t umGetGroupInUse(char_t *group)
{
	a_assert(group && *group);

/*
 *	First, check the user table
 */
	if (dbSearchStr(didUM, UM_USER_TABLENAME, UM_GROUP, group, 0) >= 0) {
		return TRUE;
	}

/*
 *	Second, check the access limit table
 */
	if (dbSearchStr(didUM, UM_ACCESS_TABLENAME, UM_GROUP, group, 0) >= 0) {
		return TRUE;
	}

	return FALSE;
}


/******************************************************************************/
/*
 *	umGetFirstGroup() - return a pointer to the first non-blank group name
 */

char_t *umGetFirstGroup(void)
{
	return umGetFirstRowData(UM_GROUP_TABLENAME, UM_NAME);
}

/******************************************************************************/
/*
 *	umGetNextGroup() -	return a pointer to the first non-blank group name
 *						following the given group name
 */

char_t *umGetNextGroup(char_t *groupLast)
{
	return umGetNextRowData(UM_GROUP_TABLENAME, UM_NAME, groupLast);
}

/******************************************************************************/
/*
 *	Returns the default access method to use for a given group
 */

accessMeth_t umGetGroupAccessMethod(char_t *group)
{
	int am, row;

	a_assert(group && *group);
	row = dbSearchStr(didUM, UM_GROUP_TABLENAME, UM_NAME, group, 0);

	if (row >= 0) {
		dbReadInt(didUM, UM_GROUP_TABLENAME, UM_METHOD, row, (int *)&am);
	} else {
		am = AM_INVALID;
	}

	return (accessMeth_t) am;
}

/******************************************************************************/
/*
 *	Set the default access method to use for a given group
 */

int	umSetGroupAccessMethod(char_t *group, accessMeth_t am)
{
	int row;

	a_assert(group && *group);
	row = dbSearchStr(didUM, UM_GROUP_TABLENAME, UM_NAME, group, 0);

	if (row >= 0) {
		return dbWriteInt(didUM, UM_GROUP_TABLENAME, UM_METHOD, row, (int) am);
	} else {
		return UM_ERR_NOT_FOUND;
	}
}

/******************************************************************************/
/*
 *	Returns the privilege mask for a given group
 */

short umGetGroupPrivilege(char_t *group)
{
	int privilege, row;

	a_assert(group && *group);
	privilege = -1;
	row = dbSearchStr(didUM, UM_GROUP_TABLENAME, UM_NAME, group, 0);

	if (row >= 0) {
		dbReadInt(didUM, UM_GROUP_TABLENAME, UM_PRIVILEGE, row, &privilege);
	}

	return (short) privilege;
}

/******************************************************************************/
/*
 *	Set the privilege mask for a given group
 */

int	umSetGroupPrivilege(char_t *group, short privilege)
{
	int row;

	a_assert(group && *group);
	row = dbSearchStr(didUM, UM_GROUP_TABLENAME, UM_NAME, group, 0);

	if (row >= 0) {
		return dbWriteInt(didUM, UM_GROUP_TABLENAME, UM_PRIVILEGE, row,
			(int)privilege);
	} else {
		return UM_ERR_NOT_FOUND;
	}
}

/******************************************************************************/
/*
 *	Returns the enabled setting for a given group.
 *	Returns FALSE if group is not found.
 */

bool_t umGetGroupEnabled(char_t *group)
{
	int disabled, row;

	a_assert(group && *group);
	row = dbSearchStr(didUM, UM_GROUP_TABLENAME, UM_NAME, group, 0);
	disabled = 1;

	if (row >= 0) {
		dbReadInt(didUM, UM_GROUP_TABLENAME, UM_DISABLE, row, &disabled);
	}

	return (bool_t) !disabled;
}

/******************************************************************************/
/*
 *	Sets the enabled setting for a given group.
 */

int umSetGroupEnabled(char_t *group, bool_t enabled)
{
	int row;

	a_assert(group && *group);
	row = dbSearchStr(didUM, UM_GROUP_TABLENAME, UM_NAME, group, 0);

	if (row >= 0) {
		return dbWriteInt(didUM, UM_GROUP_TABLENAME, UM_DISABLE, row,
			(int) !enabled);
	} else {
		return UM_ERR_NOT_FOUND;
	}
}

/******************************************************************************/
/*
 *	Returns the protected setting for a given group
 *  Returns FALSE if user is not found
 */

bool_t umGetGroupProtected(char_t *group)
{
	int protect, row;

	a_assert(group && *group);

	protect = 0;
	row = dbSearchStr(didUM, UM_GROUP_TABLENAME, UM_NAME, group, 0);
	if (row >= 0) {
		dbReadInt(didUM, UM_GROUP_TABLENAME, UM_PROT, row, &protect);
	}

	return (bool_t) protect;
}

/******************************************************************************/
/*
 *	Sets the protected setting for a given group
 */

int	umSetGroupProtected(char_t *group, bool_t protect)
{
	int row;

	a_assert(group && *group);
	row = dbSearchStr(didUM, UM_GROUP_TABLENAME, UM_NAME, group, 0);

	if (row >= 0) {
		return dbWriteInt(didUM, UM_GROUP_TABLENAME, UM_PROT, row,
			(int) protect);
	} else {
		return UM_ERR_NOT_FOUND;
	}
}


/******************************************************************************/
/*
 *	umAddAccessLimit() adds an access limit to the "access" table
 */

int	umAddAccessLimit(char_t *url, accessMeth_t am, short secure, char_t *group)
{
	int row;

	a_assert(url && *url);
	trace(3, T("UM: Adding Access Limit for <%s>\n"), url);

/*
 *	Do not allow duplicates
 */
	if (umAccessLimitExists(url)) {
		return UM_ERR_DUPLICATE;
	}

/*
 *	Add a new row to the table
 */
	if ((row = dbAddRow(didUM, UM_ACCESS_TABLENAME)) < 0) {
		return UM_ERR_GENERAL;
	}

/*
 *	Write the key field
 */
	if(dbWriteStr(didUM, UM_ACCESS_TABLENAME, UM_NAME, row, url) < 0) {
		return UM_ERR_GENERAL;
	}

/*
 *	Write the remaining fields
 */
	dbWriteInt(didUM, UM_ACCESS_TABLENAME, UM_METHOD, row, (int)am);
	dbWriteInt(didUM, UM_ACCESS_TABLENAME, UM_SECURE, row, (int)secure);
	dbWriteStr(didUM, UM_ACCESS_TABLENAME, UM_GROUP, row, group);

	return 0;
}

/******************************************************************************/
/*
 *	umDeleteAccessLimit()
 */

int	umDeleteAccessLimit(char_t *url)
{
	int row;

	a_assert(url && *url);
	trace(3, T("UM: Deleting Access Limit for <%s>\n"), url);
/*
 *	Find the row of the access limit to delete
 */
	if ((row = dbSearchStr(didUM, UM_ACCESS_TABLENAME, UM_NAME, url, 0)) < 0) {
		return UM_ERR_NOT_FOUND;
	}

	return dbDeleteRow(didUM, UM_ACCESS_TABLENAME, row);
}

/******************************************************************************/
/*
 *	umGetFirstGroup() - return a pointer to the first non-blank access limit
 */

char_t *umGetFirstAccessLimit(void)
{
	return umGetFirstRowData(UM_ACCESS_TABLENAME, UM_NAME);
}

/******************************************************************************/
/*
 *	umGetNextAccessLimit() -	return a pointer to the first non-blank
 *								access limit following the given one
 */

char_t *umGetNextAccessLimit(char_t *urlLast)
{
	return umGetNextRowData(UM_ACCESS_TABLENAME, UM_NAME, urlLast);
}

/******************************************************************************/
/*
 *	umAccessLimitExists() returns TRUE if this access limit exists
 */

bool_t	umAccessLimitExists(char_t *url)
{
	a_assert(url && *url);

	if (dbSearchStr(didUM, UM_ACCESS_TABLENAME, UM_NAME, url, 0) < 0) {
		return FALSE;
	} else {
		return TRUE;
	}
}

/******************************************************************************/
/*
 *	umGetAccessLimit() returns the Access Method for the URL
 */

accessMeth_t umGetAccessLimitMethod(char_t *url)
{
	int am, row;

	am = (int) AM_INVALID;
	row = dbSearchStr(didUM, UM_ACCESS_TABLENAME, UM_NAME, url, 0);

	if (row >= 0) {
		dbReadInt(didUM, UM_ACCESS_TABLENAME, UM_METHOD, row, &am);
	}

	return (accessMeth_t) am;
}

/******************************************************************************/
/*
 *	umSetAccessLimitMethod() - set Access Method for Access Limit
 */

int	umSetAccessLimitMethod(char_t *url, accessMeth_t am)
{
	int row;

	a_assert(url && *url);
	row = dbSearchStr(didUM, UM_ACCESS_TABLENAME, UM_NAME, url, 0);

	if (row >= 0) {
		return dbWriteInt(didUM, UM_ACCESS_TABLENAME, UM_METHOD, row, (int) am);
	} else {
		return UM_ERR_NOT_FOUND;
	}
}

/******************************************************************************/
/*
 *	umGetAccessLimitSecure() - returns secure switch for access limit
 */

short umGetAccessLimitSecure(char_t *url)
{
	int secure, row;

	a_assert(url && *url);
	secure = -1;
	row = dbSearchStr(didUM, UM_ACCESS_TABLENAME, UM_NAME, url, 0);

	if (row >= 0) {
		dbReadInt(didUM, UM_ACCESS_TABLENAME, UM_SECURE, row, &secure);
	}

	return (short)secure;
}

/******************************************************************************/
/*
 *	umSetAccessLimitSecure() - sets the secure flag for the URL
 */

int	umSetAccessLimitSecure(char_t *url, short secure)
{
	int row;

	a_assert(url && *url);
	row = dbSearchStr(didUM, UM_ACCESS_TABLENAME, UM_NAME, url, 0);

	if (row >= 0) {
		return dbWriteInt(didUM, UM_ACCESS_TABLENAME, UM_SECURE, row,
			(int)secure);
	} else {
		return UM_ERR_NOT_FOUND;
	}
}

/******************************************************************************/
/*
 *	umGetAccessLimitGroup() - returns the user group of the access limit
 */

char_t *umGetAccessLimitGroup(char_t *url)
{
	char_t	*group;
	int		row;

	a_assert(url && *url);
	group = NULL;
	row = dbSearchStr(didUM, UM_ACCESS_TABLENAME, UM_NAME, url, 0);

	if (row >= 0) {
		dbReadStr(didUM, UM_ACCESS_TABLENAME, UM_GROUP, row, &group);
	}

	return group;
}

/******************************************************************************/
/*
 *	umSetAccessLimitGroup() - sets the user group for the access limit.
 */

int	umSetAccessLimitGroup(char_t *url, char_t *group)
{
	int row;

	a_assert(url && *url);
	row = dbSearchStr(didUM, UM_ACCESS_TABLENAME, UM_NAME, url, 0);

	if (row >= 0) {
		return dbWriteStr(didUM, UM_ACCESS_TABLENAME, UM_GROUP, row, group);
	} else {
		return UM_ERR_NOT_FOUND;
	}
}

/******************************************************************************/
/*
 *	Returns the access limit to use for a given URL, by checking for URLs up
 *	the directory tree.  Creates a new string that must be deleted.
 */

char_t *umGetAccessLimit(char_t *url)
{
	char_t	*urlRet, *urlCheck, *lastChar;
	int		len;

	a_assert(url && *url);
	urlRet = NULL;
	urlCheck = bstrdup(B_L, url);
	a_assert(urlCheck);
	len = gstrlen(urlCheck);
/*
 *	Scan back through URL to see if there is a "parent" access limit
 */
	while (len && !urlRet) {
		if (umAccessLimitExists(urlCheck)) {
			urlRet = bstrdup(B_L, urlCheck);
		} else {
/*
 *	Trim the end portion of the URL to the previous directory marker
 */
			lastChar = urlCheck + len;
			lastChar--;

			while ((lastChar >= urlCheck) && ((*lastChar == '/') ||
				(*lastChar == '\\'))) {
				*lastChar = 0;
				lastChar--;
			}

			while ((lastChar >= urlCheck) && (*lastChar != '/') &&
				(*lastChar != '\\')) {
				*lastChar = 0;
				lastChar--;
			}

			len = gstrlen(urlCheck);
		}
	}
	bfree (B_L, urlCheck);

	return urlRet;
}

/******************************************************************************/
/*
 *	Returns the access method to use for a given URL
 */

accessMeth_t umGetAccessMethodForURL(char_t *url)
{
	accessMeth_t	amRet;
	char_t			*urlHavingLimit, *group;

	urlHavingLimit = umGetAccessLimit(url);
	if (urlHavingLimit) {
		group = umGetAccessLimitGroup(urlHavingLimit);

		if (group && *group) {
			amRet = umGetGroupAccessMethod(group);
		} else {
			amRet = umGetAccessLimitMethod(urlHavingLimit);
		}

		bfree(B_L, urlHavingLimit);
	} else {
		amRet = AM_FULL;
	}

	return amRet;
}

/******************************************************************************/
/*
 *	Returns TRUE if user can access URL
 */

bool_t umUserCanAccessURL(char_t *user, char_t *url)
{
	accessMeth_t	amURL;
	char_t			*group, *usergroup, *urlHavingLimit;
	short			priv;

	a_assert(user && *user);
	a_assert(url && *url);

/*
 *	Make sure user exists
 */
	if (!umUserExists(user)) {
		return FALSE;
	}

/*
 *	Make sure user is enabled
 */
	if (!umGetUserEnabled(user)) {
		return FALSE;
	}

/*
 *	Make sure user has sufficient privileges (any will do)
 */
	usergroup = umGetUserGroup(user);
	priv = umGetGroupPrivilege(usergroup);
	if (priv == 0) {
		return FALSE;
	}

/*
 *	Make sure user's group is enabled
 */
	if (!umGetGroupEnabled(usergroup)) {
		return FALSE;
	}

/*
 *	The access method of the user group must not be AM_NONE
 */
	if (umGetGroupAccessMethod(usergroup) == AM_NONE) {
		return FALSE;
	}

/*
 *	Check to see if there is an Access Limit for this URL
 */
	urlHavingLimit = umGetAccessLimit(url);
	if (urlHavingLimit) {
		amURL = umGetAccessLimitMethod(urlHavingLimit);
		group = umGetAccessLimitGroup(urlHavingLimit);
		bfree(B_L, urlHavingLimit);
	} else {
/*
 *		If there isn't an access limit for the URL, user has full access
 */
		return TRUE;
	}

/*
 *	If the access method for the URL is AM_NONE then
 *	the file "doesn't exist".
 */
	if (amURL == AM_NONE) {
		return FALSE;
	}

/*
 *	If Access Limit has a group specified, then the user must be a
 *	member of that group
 */
	if (group && *group) {
#ifdef qHierarchicalAccess
      /*
       * If we are compiling with the hierarchical access extensions, we
       * instead call the user-provided function that checks to see whether
       * the current user's access level is greater than or equal to the
       * access level required for this URL.
       */
      return dmfCanAccess(usergroup, group);

#else
		if (usergroup && (gstrcmp(group, usergroup) != 0)) {
			return FALSE;

		}
#endif
	}

/*
 *	Otherwise, user can access the URL
 */
	return TRUE;

}

/******************************************************************************/
/*
 *	Returns TRUE if given name has only valid chars
 */

static bool_t umCheckName(char_t *name)
{
	a_assert(name && *name);

	if (name && *name) {
		while (*name) {
			if (gisspace((unsigned char)*name)) {
				return FALSE;
			}

			name++;
		}

		return TRUE;
	}

	return FALSE;
}

/******************************************************************************/