diff options
Diffstat (limited to 'lib/libadmin')
-rw-r--r-- | lib/libadmin/Makefile | 61 | ||||
-rw-r--r-- | lib/libadmin/authdb.c | 2467 | ||||
-rw-r--r-- | lib/libadmin/error.c | 109 | ||||
-rw-r--r-- | lib/libadmin/strlist.c | 46 | ||||
-rw-r--r-- | lib/libadmin/template.c | 820 | ||||
-rw-r--r-- | lib/libadmin/util.c | 1340 |
6 files changed, 4843 insertions, 0 deletions
diff --git a/lib/libadmin/Makefile b/lib/libadmin/Makefile new file mode 100644 index 00000000..68029ce2 --- /dev/null +++ b/lib/libadmin/Makefile @@ -0,0 +1,61 @@ +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +# The admin libraries + +MCOM_ROOT=../../.. + +MODULE=LibAdmin +MODULE_CFLAGS=-DENCRYPT_PASSWORDS -DUSE_ADMSERV + +include ../../nsdefs.mk + +OBJDEST=$(OBJDIR)/lib/libadmin + +ifeq ($(ARCH), WINNT) +LIBS=$(OBJDIR)/lib/libadmin.lib +else +LIBS=$(OBJDIR)/lib/libadmin.a +endif + +OBJS=$(addprefix $(OBJDEST)/, admconf.o form_get.o error.o admlog.o \ + magconf.o ns-util.o objconf.o password.o \ + referer.o template.o util.o \ + hinstall.o admserv.o install.o nsnews.o \ + commit.o pcontrol.o get_msg.o \ + multconf.o httpcon.o authdb.o usrlists.o \ + dstats.o backup.o cluster.o \ + keyconf.o strlist.o $(OSOBJS)) + +# moved files [to libadminutil] : form_post.o strlist.o distadm.o cron_conf.o +# candidate for moing: admlog.o error.o admserv.o +# replaced files: error.o [by libadminutil/errRpt.c] +# removed for lack of ndbm support from binary release of libdbm.... userdb.o +#!! nsnews.o does not work anymore. + +all: $(OBJDEST) $(LIBS) + +$(LIBS): $(addprefix $(MCOM_ROOT)/ldapserver/include/libadmin/, \ + hadm_msgs.i la_msgs.i) + +include ../../nsconfig.mk + +MCC_INCLUDE += $(ADMINUTIL_INCLUDE) + +ifeq ($(ARCH), HPUX) +CC=$(CCC) +endif + +$(OBJDEST): + mkdir -p $(OBJDEST) + +$(LIBS): $(OBJS) + rm -f $@ + $(AR) $(OBJS) + $(RANLIB) $@ + +include $(INCLUDE_DEPENDS) diff --git a/lib/libadmin/authdb.c b/lib/libadmin/authdb.c new file mode 100644 index 00000000..8aff4ca8 --- /dev/null +++ b/lib/libadmin/authdb.c @@ -0,0 +1,2467 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * authdb.c: Functions to aid in user/group database admin + * + * These things leak memory like a sieve. + * + * Ben Polk + * (blame Mike McCool for functions with an MLM) + */ + +#ifdef XP_UNIX +#include <dirent.h> +#endif /* WIN32? */ + +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> +#include <stdio.h> +#include "base/shexp.h" +#include "base/util.h" +#include "libadminutil/admutil.h" +#include "libadmin/libadmin.h" + +#include "libaccess/nsgmgmt.h" +#include "libaccess/nsumgmt.h" +/* XXX MLM - This shouldn't have to define itself as private. */ +#define __PRIVATE_NSADB +#include "libaccess/nsadb.h" +#include "libaccess/nsamgmt.h" +#include "libaccess/aclerror.h" +#include "libaccess/aclbuild.h" +#include "libaccess/acladmin.h" +#include "usrlists.h" + +#define BUF_SIZE 10 + +void list_authdbs(char *fullpath, char *partialpath); + +static char **list; +static int listsize; +static int curentry; + +/* + * Rights we know about. This should be moved out to some + * external location. Perhaps obj.conf? + */ +NSAPI_PUBLIC char *acl_read_rights[] = +{ + "GET", + "HEAD", + "POST", + "INDEX", +#ifdef MCC_PROXY + "CONNECT", +#endif + NULL +}; + +NSAPI_PUBLIC char *acl_write_rights[] = +{ + "PUT", + "DELETE", + "MKDIR", + "RMDIR", + "MOVE", + NULL +}; + + +/* + * passfilter - function returns non-zero if the regular expression + * passed in matches the string passed in. + */ +static int passfilter(char *str, char *regexp) +{ + if (!str) + return 0; /* NULL string never matches */ + else if (!regexp) + return 1; /* NULL regexp matches everything */ + else + return(!shexp_casecmp(str, regexp)); +} + +NSAPI_PUBLIC char **list_auth_dbs(char *fullpath) +{ + list = new_strlist(BUF_SIZE); + listsize = BUF_SIZE; + curentry = 0; + list_authdbs(fullpath, ""); + + return(list); +} + +NSAPI_PUBLIC void output_authdb_selector(char *path, char *element, char *current) { + char **pathlist = list_auth_dbs(path); + int currentnum = -1; + int plen = path ? strlen(path) : 0; + register int x; + + /* + * If the 'current' string begins with the 'path' string, remove the + * 'path' prefix. + */ + if (!strncmp(current, path, plen)) { + current += plen; + if (*current == FILE_PATHSEP) ++current; + } + + if (pathlist[0]) /* Is there at least one database? */ + { + /* Find current selection in list of databases. */ + for(x=0; pathlist[x]; x++) { + if(!strcmp(current, pathlist[x])) { + currentnum = x; + continue; + } + } + +/* BONEHEAD */ + fprintf(stdout, "<SELECT name=\"%s\" %s>", + element, (x>SELECT_OVERFLOW) ? "size=5" : ""); + + /* If the current selection is in there, put it first. */ + if(currentnum != -1) { + fprintf(stdout, "<OPTION value=\"%s\" SELECTED>%s\n", + pathlist[currentnum], pathlist[currentnum]); + + } + for(x=0; pathlist[x]; x++) { + if (x == currentnum) + continue; + + fprintf(stdout, "<OPTION value=\"%s\">%s\n", + pathlist[x], pathlist[x]); + } + fprintf(stdout, "</SELECT>"); + } else { + fprintf(stdout, "<b>No databases found.</b>"); + } +} + +NSAPI_PUBLIC char *get_current_authdb() +{ + char **config = get_adm_config(); + return(STRDUP(config[3])); +} + +NSAPI_PUBLIC void set_current_authdb(char *current) +{ + char **config = get_adm_config(); + config[3] = STRDUP(current); + write_adm_config(config); +} + +void list_authdbs(char *fullpath, char *partialpath) +{ + int stat_good; + struct stat finfo; + char **dirlisting; + char *path = (char *)MALLOC(strlen(fullpath)+strlen(partialpath)+2); + + sprintf(path, "%s%c%s", fullpath, FILE_PATHSEP, partialpath); + if( !(dirlisting = list_directory(path,0))) + return; + else { + register int x; + char *entry, *newppath; + + for(x=0; dirlisting[x]; x++) { + entry = (char *)MALLOC(strlen(path)+strlen(dirlisting[x])+2); + sprintf(entry, "%s%s", path, dirlisting[x]); + +#ifdef XP_UNIX + stat_good = (lstat(entry, &finfo) == -1 ? 0 : 1); +#else /* WIN32 */ + stat_good = (stat(entry, &finfo) == -1 ? 0 : 1); +#endif /* XP_UNIX */ + + if(!stat_good) + continue; + newppath = (char *)MALLOC(strlen(partialpath)+strlen(dirlisting[x])+3); + + if(S_ISDIR(finfo.st_mode)) { + sprintf(newppath, "%s%s", partialpath, dirlisting[x]); + curentry++; + + if(!(curentry < listsize)) { + listsize += BUF_SIZE; + list = grow_strlist(list, listsize); + } + list[curentry-1] = STRDUP(newppath); + list[curentry] = NULL; + } + + FREE(entry); + FREE(newppath); + } + } +} + +/* Get the userdb directory. (V1.x) */ +NSAPI_PUBLIC char *get_userdb_dir(void) +{ + char *userdb; + char line[BIG_LINE]; + +#ifdef USE_ADMSERV + char *tmp = getenv("NETSITE_ROOT"); + + sprintf(line, "%s%cuserdb", tmp, FILE_PATHSEP); +#else + char *tmp = get_mag_var("#ServerRoot"); + + sprintf(line, "%s%cadmin%cuserdb", tmp, FILE_PATHSEP, FILE_PATHSEP); +#endif + userdb = STRDUP(line); + return userdb; +} + +/* Get the httpacl directory. (V2.x) */ +NSAPI_PUBLIC char *get_httpacl_dir(void) +{ + char *httpacl; + char line[BIG_LINE]; + +#ifdef USE_ADMSERV + char *tmp = getenv("NETSITE_ROOT"); + + sprintf(line, "%s%chttpacl", tmp, FILE_PATHSEP); +#else + char *tmp = get_mag_var("#ServerRoot"); + + sprintf(line, "%s%cadmin%chttpacl", tmp, FILE_PATHSEP, FILE_PATHSEP); +#endif + httpacl = STRDUP(line); + return httpacl; +} + +/* Get the authdb directory. (V2.x) */ +NSAPI_PUBLIC char *get_authdb_dir(void) +{ + char *authdb; + char line[BIG_LINE]; + +#ifdef USE_ADMSERV + char *tmp = getenv("NETSITE_ROOT"); + + sprintf(line, "%s%cauthdb", tmp, FILE_PATHSEP); +#else + char *tmp = get_mag_var("#ServerRoot"); + + sprintf(line, "%s%cadmin%cauthdb", tmp, FILE_PATHSEP, FILE_PATHSEP); +#endif + authdb = STRDUP(line); + return authdb; +} +/* + * groupOrUser - function sets its return variable flags + * based on whether the name passed in is + * a user or a group in the specified database. + * It could be both, although the entry form + * are intended to prohibit this. + * Returns: 0 if no error occurs, something else otherwise. + */ +NSAPI_PUBLIC int groupOrUser(char *db_path, char *name, int *is_user, int *is_group) +{ + int rv = 1; + UserObj_t *uoptr; + GroupObj_t *goptr; + void *padb; + + if (name && is_user && is_group) { + *is_user = 0; + *is_group = 0; + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (!rv) { + + rv = nsadbFindByName(NULL, padb, name, AIF_USER, (void **)&uoptr); + if (rv == AIF_USER) { + *is_user = 1; + } + + rv = nsadbFindByName(NULL, padb, name, AIF_GROUP, (void **)&goptr); + if (rv == AIF_GROUP) { + *is_group = 1; + } + + nsadbClose(padb, 0); + } + } + + return rv; +} + +/* + * getfullname - function to get the fullname of a user. + * Return: Returns 0 if it works, something else if it fails. + */ +NSAPI_PUBLIC int getfullname(char *db_path, char *user, char **fullname) { + int rv; + UserObj_t *uoptr; + void *padb; + + if (db_path && user) + { + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv == 0) { + rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr); + if (rv == AIF_USER) { + *fullname = (uoptr->uo_rname != 0) ? STRDUP((char *)uoptr->uo_rname) + : STRDUP(""); + } + else + rv = 1; + nsadbClose(padb, 0); + } + } + else + rv = 1; + + return rv; +} + +/* + * setfullname - function to set the fullname for the specified user. + * Return: Returns 0 if it works, something else if it fails. + */ +NSAPI_PUBLIC int setfullname(char *db_path, char *user, char *fullname) { + int rv; + UserObj_t *uoptr; + void *padb; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) { + report_error(SYSTEM_ERROR, "Failed To Open Database", + "An error occurred while trying to update " + "the user's fullname in the database."); + } else { + /* See if the user already exists, if so, update it. */ + rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr); + if (rv == AIF_USER) { + uoptr->uo_rname = (NTS_t)fullname; + } else { + /* User doesn't exist, so we've failed. */ + report_error(SYSTEM_ERROR, user, + "Unable to change this user's fullname, " + "user was not found in the database."); + rv = 1; + } + + if (uoptr) { + rv = nsadbModifyUser(NULL, padb, uoptr); + if (rv < 0) + report_error(SYSTEM_ERROR, user, + "A database error occurred while " + "trying to change the user fullname."); + } + nsadbClose(padb, 0); + } + return rv; +} + +/* Set a user's login name MLM*/ +NSAPI_PUBLIC int setusername(char *db_path, char *user, char *newname) { + int rv; + UserObj_t *uoptr; + void *padb; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) { + report_error(SYSTEM_ERROR, "Failed To Open Database", + "An error occurred while trying to update " + "the user's fullname in the database."); + } else { + /* See if the user already exists, if so, update it. */ + rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr); + if (rv != AIF_USER) { + /* User doesn't exist, so we've failed. */ + report_error(SYSTEM_ERROR, user, + "Unable to change this user's fullname, " + "user was not found in the database."); + rv = 1; + } + if (uoptr) { + rv = userRename(NULL, ((AuthDB_t *)padb)->adb_userdb, + uoptr, (NTS_t)newname); + + if (rv < 0) + report_error(SYSTEM_ERROR, user, + "A database error occurred while " + "trying to change the login name."); + } + nsadbClose(padb, 0); + } + return rv; +} + +/* + * addusertogroup - function to add a user to a group + * Return: Returns 0 if it works, something else if it fails. + */ +NSAPI_PUBLIC int addusertogroup(char *db_path, char *user, char *group) { + int rv; + UserObj_t *uoptr; + GroupObj_t *goptr; + void *padb; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) { + report_error(SYSTEM_ERROR, "Failed To Open Database", + "An error occurred while trying to add " + "user to a group."); + } else { + /* See if the user and group exist. */ + rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr); + rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr); + if (goptr == 0) { + report_error(INCORRECT_USAGE, group, + "The group was not found."); + } + else if (uoptr == 0) { + report_error(INCORRECT_USAGE, user, + "The user was not found."); + } + else { + rv = nsadbAddUserToGroup(NULL, padb, goptr, uoptr); + } + + nsadbClose(padb, 0); + } + return rv; +} + +/* + * addgrouptogroup - function to add a group to a group + * Return: Returns 0 if it works, something else if it fails. + */ +NSAPI_PUBLIC int addgrouptogroup(char *db_path, char *memgroup, char *group) { + int rv; + GroupObj_t *goptr; + GroupObj_t *mem_goptr; + void *padb; + + if (!strcmp(memgroup, group)) { + report_error(INCORRECT_USAGE, group, + "You can't add a group to itself."); + } + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) { + report_error(SYSTEM_ERROR, "Failed To Open Database", + "An error occurred while trying to add " + "group to a group."); + } else { + /* See if the groups exist. */ + rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr); + rv = nsadbFindByName(NULL, + padb, memgroup, AIF_GROUP, (void **)&mem_goptr); + if (goptr == 0) { + report_error(INCORRECT_USAGE, group, + "The target group was not found."); + } + else if (mem_goptr == 0) { + report_error(INCORRECT_USAGE, memgroup, + "The group to add was not found."); + } + else { + rv = nsadbAddGroupToGroup(NULL, padb, goptr, mem_goptr); + } + + nsadbClose(padb, 0); + } + return rv; +} + +/* + * remuserfromgroup - function to remove a user from a group + * Return: Returns 0 if it works, something else if it fails. + */ +NSAPI_PUBLIC int remuserfromgroup(char *db_path, char *user, char *group) { + int rv; + UserObj_t *uoptr; + GroupObj_t *goptr; + void *padb; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) { + report_error(SYSTEM_ERROR, "Failed To Open Database", + "An error occurred while trying to add " + "user to a group."); + } else { + /* See if the user and group exist. */ + rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr); + rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr); + if (goptr == 0) { + report_error(SYSTEM_ERROR, group, + "The group was not found."); + } + else if (uoptr == 0) { + report_error(SYSTEM_ERROR, user, + "The user was not found."); + } + else { + rv = nsadbRemUserFromGroup(NULL, padb, goptr, uoptr); + if (rv) + report_error(SYSTEM_ERROR, "Error taking out user", + "An error occured trying to take " + "the user out of the group."); + } + + nsadbClose(padb, 0); + } + return rv; +} + +/* + * remgroupfromgroup - function to remove a group to a group + * Return: Returns 0 if it works, something else if it fails. + */ +NSAPI_PUBLIC int remgroupfromgroup(char *db_path, char *memgroup, char *group) { + int rv; + GroupObj_t *goptr; + GroupObj_t *mem_goptr; + void *padb; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) { + report_error(SYSTEM_ERROR, "Failed To Open Database", + "An error occurred while trying to remove " + "a group from a group."); + } else { + /* See if the groups exist. */ + rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr); + rv = nsadbFindByName(NULL, + padb, memgroup, AIF_GROUP, (void **)&mem_goptr); + if (goptr == 0) { + report_error(SYSTEM_ERROR, group, + "The target group was not found."); + } + else if (mem_goptr == 0) { + report_error(SYSTEM_ERROR, memgroup, + "The group to remove was not found."); + } + else { + rv = nsadbRemGroupFromGroup(NULL, padb, goptr, mem_goptr); + } + + nsadbClose(padb, 0); + } + return rv; +} + +/* + * setpw - function to set the password for the specified user. + * Return: Returns 0 if it works, something else if it fails. + */ +NSAPI_PUBLIC int setpw(char *db_path, char *user, char *pwd) { + int rv; + UserObj_t *uoptr = 0; + void *padb; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) { + report_error(SYSTEM_ERROR, "Failed To Open Database", + "An error occurred while trying to add " + "the password to the database."); + } else { + /* See if the user already exists, if so, update it. */ + rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr); + if (uoptr != 0) { + uoptr->uo_pwd = (NTS_t)STRDUP(pw_enc(pwd)); + } else { + /* User doesn't exist, so we've failed. */ + report_error(SYSTEM_ERROR, user, + "Unable to change this user's password, " + "user was not found in the database."); + rv = 1; + } + + if (uoptr) { + rv = nsadbModifyUser(NULL, padb, uoptr); + if (rv < 0) + report_error(SYSTEM_ERROR, user, + "A database error occurred while " + "trying to change the user password."); + } + nsadbClose(padb, 0); + } + return rv; +} + +/* + * setdbpw - function to set the password on the special user + * who's password is used as the database password. + * If the password passed in is NULL, the user is + * removed or not created. + * If the password is not NULL, then the user will + * be created if needed, and it's password set to + * the one passed in. + * + * Return: Returns 0 if it works, something else if it fails. + */ +NSAPI_PUBLIC int setdbpw(char *db_path, char *pwd) +{ + int rv; + UserObj_t *uoptr = 0; + void *padb; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) { + report_error(SYSTEM_ERROR, "Failed To Open Database", + "An error occurred while trying to add " + "the password to the database."); + } + /* + * If NULL pwd, remove the user if it exists. + */ + else if (pwd == NULL) { + rv = nsadbRemoveUser(NULL, padb, DBPW_USER); + nsadbClose(padb, 0); + + /* + * If we get success(0) or a no such user error(NSAERRNAME) + * we're happy. + */ + if (rv != 0 && rv != NSAERRNAME) { + report_error(SYSTEM_ERROR, "Remove Password Failed", + "An error occurred while trying to remove " + "the password for the database."); + } + } else { + /* See if the user already exists, if so, just update it. */ + rv = nsadbFindByName(NULL, padb, DBPW_USER, AIF_USER, (void **)&uoptr); + if (uoptr == 0) { + /* User doesn't exist, so add it. */ + uoptr = userCreate((NTS_t)DBPW_USER, (NTS_t)pw_enc(pwd), (NTS_t)DBPW_USER); + if (uoptr == 0) { + report_error(SYSTEM_ERROR, "Failed To Update Database", + "An error occurred while trying to add " + "the password to the database."); + rv = 1; + } + else { + rv = nsadbCreateUser(NULL, padb, uoptr); + } + } else { + uoptr->uo_pwd = (NTS_t)STRDUP(pw_enc(pwd)); + rv = nsadbModifyUser(NULL, padb, uoptr); + } + + nsadbClose(padb, 0); + + if (uoptr) { + if (rv < 0) { + report_error(SYSTEM_ERROR, "Failed To Set Database Password", + "An error occurred while trying to save " + "the password in the database."); + rv = 1; + } + userFree(uoptr); + } + } + return rv; +} + +/* + * checkdbpw - Return TRUE if the password is correct, or database + * doesn't have one, because the password user isn't there. + * Return FALSE if required password is not correct. + */ +NSAPI_PUBLIC int checkdbpw(char *db_path, char *pwd) +{ + int rv; + UserObj_t *uoptr = 0; + void *padb; + int fpwOK = 0; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv == 0) { + rv = nsadbFindByName(NULL, padb, DBPW_USER, AIF_USER, (void **)&uoptr); + if (uoptr == 0) { + fpwOK = 1; /* Password userid isn't there, so none required. */ + } else { + if (pwd == NULL) + fpwOK = 0; /* PW user exists, no pw passed in, return false. */ + else { + if (pw_cmp(pwd, (char *)uoptr->uo_pwd)) + fpwOK = 0; /* passwords are different, so return false. */ + else + fpwOK = 1; /* passwords are the same, so return true. */ + } + userFree(uoptr); + } + nsadbClose(padb, 0); + } + return fpwOK; +} + +/* + * Create a link to another CGI: + * val - value text on the link + * targ - name of the CGI to start + * arg - argument to pass to the CGI + */ +void output_cgi_link(char *val, char *trg, char *arg) +{ + char line[BIG_LINE]; + sprintf(line, "%s?%s", trg, arg); + printf("<a href=index?options+acss+%s target='options'>%s</a>", + util_uri_escape(NULL, line), val); +} + +/* + * groupEnumCB - callback function from libaccess group enumerator + */ +static int groupEnumCB (NSErr_t * errp, + void * padb, void *parg, GroupObj_t *goptr) +{ + if (goptr && goptr->go_name && strlen((char *)goptr->go_name)) + ulsAddToList(parg, goptr->go_gid, (char *)goptr->go_name); + + return 0; /* 0: continue enumeration */ +} + +/* + * userEnumCB - callback function from libaccess group enumerator + */ +static int userEnumCB (NSErr_t * errp, + void * padb, void *parg, UserObj_t *uoptr) +{ + if (uoptr && uoptr->uo_name && strlen((char *)uoptr->uo_name)) + ulsAddToList(parg, uoptr->uo_uid, (char *)uoptr->uo_name); + + return 0; /* 0: continue enumeration */ +} + +/* + * idfound - horribly inefficient scan through the idlist table + * returning true if the specified id is found, false + * otherwise. + */ +int idfound(int id, int *idlist, int count) +{ + int i; + for (i = 0; i < count; ++i) { + if (id == idlist[i]) + return 1; + } + return 0; +} + +void output_groups_user_is_in(char *db_path, char *user) +{ + int rv; + UserObj_t *uoptr = 0; + GroupObj_t *goptr = 0; + void *padb; + USI_t *gidlist; + int i; + int id; + char *group; + char *gname; + int groupCount; + char line[BIG_LINE]; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) { + report_error(SYSTEM_ERROR, db_path, + "Failed to open database while trying " + "to list group membership."); + } else { + /* See if the user exists. */ + rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr); + if (uoptr == 0) { + /* User doesn't exist, so we've failed. */ + report_error(SYSTEM_ERROR, user, + "Unable to find user when trying to " + "list group membership."); + rv = 1; + } else { + groupCount = UILCOUNT(&uoptr->uo_groups); + if (groupCount > 0) { + void *DirectlyInList; + void *IndirectlyInList; + ulsAlloc(&DirectlyInList); + ulsAlloc(&IndirectlyInList); + + gidlist = UILLIST(&uoptr->uo_groups); + for (i = 0; i < groupCount; ++i) { + rv = nsadbIdToName(NULL, + padb, gidlist[i], AIF_GROUP, &gname); + if (rv >= 0) { + rv = nsadbFindByName(NULL, padb, gname, AIF_GROUP, + (void **)&goptr); + } + if (goptr != 0) { + if (goptr->go_name && strlen((char *)goptr->go_name)) { + if (idfound(uoptr->uo_uid, + (int*)UILLIST(&goptr->go_users), + UILCOUNT(&goptr->go_users))) { + ulsAddToList(DirectlyInList, goptr->go_gid, + (char *)goptr->go_name); + } + else { + ulsAddToList(IndirectlyInList, goptr->go_gid, + (char *)goptr->go_name); + } + } + groupFree(goptr); + goptr = 0; + } + } + ulsSortName(DirectlyInList); + ulsGetCount(DirectlyInList, &groupCount); + for (i=0; i<groupCount; ++i) { + group = NULL; + ulsGetEntry(DirectlyInList, i, &id, &group); + if (group) { + printf("<tr><td>"); + printf("Member of <b>%s</b></td><td>", group); + sprintf(line, "group=%s", group); + output_cgi_link("Edit Group", "grped", line); + printf("</td><td>"); + sprintf(line, "remfromgrp_but=1&memuser=%s&group=%s", + user, group); + output_cgi_link("Remove from Group", "grped", line); + printf("</td>\n"); + } + } + ulsSortName(IndirectlyInList); + ulsGetCount(IndirectlyInList, &groupCount); + for (i=0; i<groupCount; ++i) { + group = NULL; + ulsGetEntry(IndirectlyInList, i, &id, &group); + if (group) { + printf("<tr><td>"); + printf("Indirect member of <b>%s</b></td><td>", group); + sprintf(line, "group=%s", group); + output_cgi_link("Edit Group", "grped", group); + printf("</td><td>"); + sprintf(line, "addtogrp_but=1&memuser=%s&group=%s", + user, group); + output_cgi_link("Add to Group", "grped", line); + printf("</td>\n"); + } + } + ulsFree(&DirectlyInList); + ulsFree(&IndirectlyInList); + } + } + } + return; +} + +/* + * output a table with the groups the user isn't a member of + */ +void output_nonmembership(char *db_path, char *user) +{ + int rv; + UserObj_t *uoptr = 0; + void *padb; + USI_t *gidlist; + int i; + int id; + char *group; + int groupCount; + char line[BIG_LINE]; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) { + report_error(SYSTEM_ERROR, db_path, + "Failed to open database while trying " + "to list group membership."); + } else { + rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr); + if (uoptr == 0) { + report_error(SYSTEM_ERROR, user, + "Unable to find user when trying to " + "list group membership."); + rv = 1; + } else { + void *sortList; + + ulsAlloc(&sortList); + rv = nsadbEnumerateGroups(NULL, padb, + (void *)sortList, groupEnumCB); + + ulsSortName(sortList); + ulsGetCount(sortList, &groupCount); + + if (groupCount > 0) { + gidlist = UILLIST(&uoptr->uo_groups); + for (i=0; i<groupCount; ++i) { + group = NULL; + ulsGetEntry(sortList, i, &id, &group); + if (group && !idfound(id, (int*)gidlist, UILCOUNT(&uoptr->uo_groups))){ + printf("<tr><td>"); + printf("Not a member of <b>%s</b></td><td>", group); + sprintf(line, "group=%s", group); + output_cgi_link("Edit Group", "grped", line); + printf("</td><td>"); + sprintf(line, "addtogrp_but=1&memuser=%s&group=%s", + user, group); + output_cgi_link("Add to Group", "grped", line); + printf("</td>\n"); + } + } + } + ulsFree(&sortList); + userFree(uoptr); + } + } + return; +} + +/* + * output_group_membership - output a table showing which + * groups a user is in. + */ +void output_group_membership(char *db_path, char *user) +{ + printf("<table border=1><caption align=left>\n"); + printf("<b>%s group membership:</b>", user); + printf("</caption>\n"); + output_groups_user_is_in(db_path, user); + output_nonmembership(db_path, user); + printf("</table>\n"); +} + +void output_grpgroup_membership(char *db_path, char *group, char *filter) +{ + int rv; + GroupObj_t *goptr = 0; + void *padb; + USI_t *gidlist; + int i; + int id; + char *gname; + char *memgroup; + int groupCount; + char line[BIG_LINE]; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) { + report_error(SYSTEM_ERROR, db_path, + "Failed to open database while trying " + "to list group membership."); + } else { + /* See if the group exists. */ + rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr); + if (goptr == 0) { + /* Group doesn't exist, so we've failed. */ + report_error(SYSTEM_ERROR, group, + "Unable to find group when trying to " + "list group membership."); + rv = 1; + } else { + groupCount = UILCOUNT(&goptr->go_groups); + if (groupCount > 0) { + void *sortList; + ulsAlloc(&sortList); + + printf("<table border=1><caption align=left>\n"); + printf("<b>%s has these group members:</b>", group); + printf("</caption>\n"); + gidlist = UILLIST(&goptr->go_groups); + for (i = 0; i < groupCount; ++i) { + rv = nsadbIdToName(NULL, + padb, gidlist[i], AIF_GROUP, &gname); + if ((rv >= 0) && (gname != 0) && (strlen(gname) != 0)) { + ulsAddToList(sortList, gidlist[i], gname); + } + } + ulsSortName(sortList); + ulsGetCount(sortList, &groupCount); + for (i=0; i<groupCount; ++i) { + memgroup = NULL; + ulsGetEntry(sortList, i, &id, &memgroup); + if (memgroup && passfilter(memgroup, filter)) { + printf("<tr><td>"); + printf("<b>%s</b></td><td>", memgroup); + sprintf(line, "group=%s", memgroup); + output_cgi_link("Edit Group", "grped", line); + printf("</td><td>"); + sprintf(line, "remfromgrp_but=1&memgroup=%s&group=%s", + memgroup, group); + output_cgi_link("Remove from Group", "grped", line); + printf("</td>\n"); + } + } + printf("</table>\n"); + ulsFree(&sortList); + } else { + printf("<b>This group has no group members.</b>"); + } + groupFree(goptr); + } + nsadbClose(padb, 0); + } + return; +} + +/* + * Output a table showing the user members of a group. + */ +NSAPI_PUBLIC void output_user_membership(char *db_path, char *group, char *filter) +{ + int rv; + GroupObj_t *goptr = 0; + void *padb; + USI_t *uidlist; + char *user; + int i; + int id; + char *memuser; + int userCount; + char line[BIG_LINE]; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) { + report_error(SYSTEM_ERROR, db_path, + "Failed to open database while trying " + "to list user membership."); + } else { + /* See if the group exists. */ + rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr); + if (goptr == 0) { + /* Group doesn't exist, so we've failed. */ + nsadbClose(padb, 0); + report_error(SYSTEM_ERROR, group, + "Unable to find group when trying to " + "list user membership."); + rv = 1; + } else { + userCount = UILCOUNT(&goptr->go_users); + if (userCount > 0) { + void *sortList; + ulsAlloc(&sortList); + + printf("<table border=1><caption align=left>\n"); + printf("<b>%s has these user members:</b>", group); + printf("</caption>\n"); + uidlist = UILLIST(&goptr->go_users); + for (i = 0; i < userCount; ++i) { + rv = nsadbIdToName(NULL, + padb, uidlist[i], AIF_USER, &user); + if ((rv >= 0) && (user != 0) && (strlen(user) != 0)) { + ulsAddToList(sortList, uidlist[i], user); + } + } + nsadbClose(padb, 0); + ulsSortName(sortList); + ulsGetCount(sortList, &userCount); + for (i=0; i<userCount; ++i) { + memuser = NULL; + ulsGetEntry(sortList, i, &id, &memuser); + if (memuser && passfilter(memuser, filter)) { + printf("<tr><td>"); + printf("<b>%s</b></td><td>", memuser); + sprintf(line, "user=%s", memuser); + output_cgi_link("Edit User", "usred", line); + printf("</td><td>"); + sprintf(line, "remfromgrp_but=1&memuser=%s&group=%s", + memuser, group); + output_cgi_link("Remove from Group", "grped", line); + printf("</td>\n"); + } + } + printf("</table>\n"); + ulsFree(&sortList); + } else { + nsadbClose(padb, 0); + printf("<b>This group has no user members.</b>"); + } + } + } + return; +} + +/* + * Output a group showing all users. + */ +NSAPI_PUBLIC int output_users_list(char *db_path, char *filter) +{ + int rv; + void *padb; + int i; + int id; + char *user; + int userCount; + char line[BIG_LINE]; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) + report_error(SYSTEM_ERROR, db_path, + "Failed to open database while trying " + "to list users."); + else { + void *sortList; + + ulsAlloc(&sortList); + rv = nsadbEnumerateUsers(NULL, padb, (void *)sortList, userEnumCB); + nsadbClose(padb, 0); + ulsSortName(sortList); + ulsGetCount(sortList, &userCount); + + if (userCount > 0) { + + printf("<table border=1><caption align=left>\n"); + printf("<b>User List:</b>"); + printf("</caption>\n"); + + for (i=0; i<userCount; ++i) { + user = NULL; + ulsGetEntry(sortList, i, &id, &user); + if (user && passfilter(user, filter)) { + printf("<tr><td>"); + printf("<b>%s</b></td><td>", user); + sprintf(line, "user=%s", user); + output_cgi_link("Edit User", "usred", line); + printf("</td><td>\n"); + output_cgi_link("Remove User", "usrrem", line); + printf("</td>\n"); + } + } + printf("</table>\n"); + } else { + printf("<b>There are no users in the database.</b>"); + } + ulsFree(&sortList); + } + return rv; +} + +/* + * Output a table showing all groups. + */ +NSAPI_PUBLIC int output_groups_list(char *db_path, char *filter) +{ + int rv; + void *padb; + int i; + int id; + char *group; + int groupCount; + char line[BIG_LINE]; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) + report_error(SYSTEM_ERROR, db_path, + "Failed to open database while trying " + "to list groups."); + else { + void *sortList; + + ulsAlloc(&sortList); + rv = nsadbEnumerateGroups(NULL, padb, (void *)sortList, groupEnumCB); + nsadbClose(padb, 0); + ulsSortName(sortList); + ulsGetCount(sortList, &groupCount); + + if (groupCount > 0) { + + printf("<table border=1><caption align=left>\n"); + printf("<b>Group List:</b>"); + printf("</caption>\n"); + + for (i=0; i<groupCount; ++i) { + group = NULL; + ulsGetEntry(sortList, i, &id, &group); + if ((group) && (passfilter(group, filter))) { + printf("<tr><td>"); + printf("<b>%s</b></td><td>", group); + sprintf(line, "group=%s", group); + output_cgi_link("Edit Group", "grped", line); + printf("</td><td>"); + output_cgi_link("Remove Group", "grprem", line); + printf("</td>\n"); + } + } + printf("</table>\n"); + } else { + printf("<b>There are no groups in the database.</b>"); + } + ulsFree(&sortList); + } + return rv; +} + +/* Helper function: Return a uls list of all the groups a user is in. MLM */ +void *_list_user_groups(void *padb, char *user, int group_users) +{ + int rv; + register int i; + UserObj_t *uoptr = 0; + GroupObj_t *ugoptr = 0; + GroupObj_t *goptr = 0; + void *userGroupList = NULL; + int userGroupCount= 0; + USI_t *gidlist; + char *ugname = NULL; + + if(!group_users) { + rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr); + } else { + rv = nsadbFindByName(NULL, padb, user, AIF_GROUP, (void **)&ugoptr); + } + if ((uoptr == 0) && (ugoptr == 0)) { + /* User doesn't exist, so we've failed. */ + return NULL; + } else { + if(uoptr) { + userGroupCount = UILCOUNT(&uoptr->uo_groups); + } else { + userGroupCount = UILCOUNT(&ugoptr->go_groups); + } + if (userGroupCount > 0) { + ulsAlloc(&userGroupList); + if(uoptr) { + gidlist = UILLIST(&uoptr->uo_groups); + } else { + gidlist = UILLIST(&ugoptr->go_groups); + } + + for (i = 0; i < userGroupCount; ++i) { + rv = nsadbIdToName(NULL, padb, + gidlist[i], AIF_GROUP, &ugname); + + if (rv >= 0) { + rv = nsadbFindByName(NULL, padb, ugname, AIF_GROUP, + (void **)&goptr); + } + if (goptr != 0) { + if (goptr->go_name && strlen((char *)goptr->go_name)) { + if(uoptr) { + if (idfound(uoptr->uo_uid, + (int*)UILLIST(&goptr->go_users), + UILCOUNT(&goptr->go_users))) { + ulsAddToList(userGroupList, goptr->go_gid, + (char *)goptr->go_name); + } + } else { + ulsAddToList(userGroupList, goptr->go_gid, + (char *)goptr->go_name); + } + } + groupFree(goptr); + goptr = 0; + } + } + } + } + return userGroupList; +} + +/* Output a selector box, with name "name", and make it a multiple + * selector box if multiple=1. */ +/* If user is non-null, then if it's a multiple selector, correctly highlight + * the groups the user is in. + * If group_user is 1, then the variable "user" refers to a *group* as + * a member, rather than a user. + * Highlight the item "highlight" regardless of membership (as long as + * it's non-NULL.) MLM */ +NSAPI_PUBLIC void output_group_selector(char *db_path, int group_user, + char *user, + char *highlight, char *except, + char *name, int none, int multiple) +{ + int rv; + void *padb; + int i, j, isselected; + int id; + char *group; + int groupCount; + void *userGroupList = NULL; + int userGroupCount= 0; + char *ugname = NULL; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) + report_error(SYSTEM_ERROR, db_path, + "Failed to open database while trying " + "to list groups."); + else { + void *sortList; + + ulsAlloc(&sortList); + rv = nsadbEnumerateGroups(NULL, padb, (void *)sortList, groupEnumCB); + + if((multiple) && (user)) { + userGroupList=_list_user_groups(padb, user, group_user); + if(userGroupList) { + ulsSortName(userGroupList); + ulsGetCount(userGroupList, &userGroupCount); + } + } + nsadbClose(padb, 0); + ulsSortName(sortList); + ulsGetCount(sortList, &groupCount); + + if (groupCount > 0) { + /* Make a pulldown if we can. If the size is bigger than the + * overflow value, make it a box to hack around the fact that + * the X Navigator can't scroll pulldown lists. */ + if((multiple) || (groupCount > SELECT_OVERFLOW)) { + printf("<SELECT size=5 name=%s %s>", + name, multiple? "MULTIPLE" : ""); + } else { + printf("<SELECT name=%s>", name); + } + if((!multiple) && (none)) { + printf("<OPTION value=NONE>NONE\n"); + } + + for (i=0; i<groupCount; ++i) { + group = NULL; + ugname = NULL; + isselected=0; + ulsGetEntry(sortList, i, &id, &group); + if (group) { + if((except) && (!strcmp(group, except))) + continue; + if((highlight) && (!strcmp(group, highlight))) + isselected=1; + if(userGroupList && !isselected) { + for(j=0; j < userGroupCount; j++) { + ulsGetEntry(userGroupList, j, &id, &ugname); +#if 0 + if(ugname[0] > group[0]) { + /* Both lists are sorted, therefore, if we've + * hit a letter that's after the group letter, + * it must not be here. */ + /* What can I say, it's a pathetic attempt + * on my part to mask the fact that I know + * this is inefficient. */ + break; + } +#endif + if(!strcmp(ugname, group)) { + isselected=1; + break; + } + } + } + printf("<OPTION %s>%s\n", + isselected? "SELECTED" : "", group); + } + } + printf("</SELECT>"); + } else { + printf("<b>(No groups have been created.)</b>"); + } + ulsFree(&sortList); + if(userGroupList) + ulsFree(&userGroupList); + } +} + +void *_list_group_users(void *padb, char *group, int group_users) +{ + int rv; + GroupObj_t *goptr = 0; + USI_t *uidlist; + char *user; + int i; + int userCount; + void *sortList=NULL; + + /* See if the group exists. */ + rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr); + if (goptr == 0) { + /* Group doesn't exist, so we've failed. */ + return NULL; + } else { + if(group_users) + userCount = UILCOUNT(&goptr->go_groups); + else + userCount = UILCOUNT(&goptr->go_users); + + if (userCount > 0) { + ulsAlloc(&sortList); + + if(group_users) + uidlist = UILLIST(&goptr->go_groups); + else + uidlist = UILLIST(&goptr->go_users); + + for (i = 0; i < userCount; ++i) { + if(group_users) + rv = nsadbIdToName(NULL,padb, uidlist[i], AIF_GROUP, &user); + else + rv = nsadbIdToName(NULL, padb, uidlist[i], AIF_USER, &user); + if ((rv >= 0) && (user != 0) && (strlen(user) != 0)) { + ulsAddToList(sortList, uidlist[i], user); + } + } + } + } + return sortList; +} + +/* + * Output a selector box of users. If group is non-null, highlight the + * users in that group. MLM + */ +NSAPI_PUBLIC void output_user_selector(char *db_path, char *group, + char *highlight, char *except, + char *name, int none, int multiple) +{ + int rv; + void *padb; + int i, j, isselected; + int id; + char *user; + int userCount; + void *groupUserList = NULL; + int groupUserCount= 0; + char *guname = NULL; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) + report_error(SYSTEM_ERROR, db_path, + "Failed to open database while trying " + "to list groups."); + else { + void *sortList; + + ulsAlloc(&sortList); + rv = nsadbEnumerateUsers(NULL, padb, (void *)sortList, userEnumCB); + + if((multiple) && (group)) { + groupUserList=_list_group_users(padb, group, 0); + if(groupUserList) { + ulsSortName(groupUserList); + ulsGetCount(groupUserList, &groupUserCount); + } + } + nsadbClose(padb, 0); + ulsSortName(sortList); + ulsGetCount(sortList, &userCount); + + if (userCount > 0) { + /* Make a pulldown if we can. If the size is bigger than the + * overflow value, make it a box to hack around the fact that + * the X Navigator can't scroll pulldown lists. */ + if((multiple) || (userCount > SELECT_OVERFLOW)) { + printf("<SELECT size=5 name=%s %s>", + name, multiple? "MULTIPLE" : ""); + } else { + printf("<SELECT name=%s>", name); + } + if((!multiple) && (none)) { + printf("<OPTION value=NONE>NONE\n"); + } + + for (i=0; i<userCount; ++i) { + user = NULL; + guname = NULL; + isselected=0; + ulsGetEntry(sortList, i, &id, &user); + if (user) { + if((except) && (!strcmp(user, except))) + continue; + if((highlight) && (!strcmp(user, highlight))) + isselected=1; + if(groupUserList && !isselected) { + for(j=0; j < groupUserCount; j++) { + ulsGetEntry(groupUserList, j, &id, &guname); +#if 0 + if(guname[0] > user[0]) { + /* Both lists are sorted, therefore, if we've + * hit a letter that's after the group letter, + * it must not be here. */ + /* What can I say, it's a pathetic attempt + * on my part to mask the fact that I know + * this is inefficient. */ + break; + } +#endif + if(!strcmp(guname, user)) { + isselected=1; + break; + } + } + } + printf("<OPTION %s>%s\n", + isselected? "SELECTED" : "", user); + } + } + printf("</SELECT>"); + } else { + printf("<b>(No users have been created.)</b>"); + } + ulsFree(&sortList); + if(groupUserList) + ulsFree(&groupUserList); + } +} + + +int _item_in_list(char *item, char **list) +{ + register int i; + if(!list) return -1; + for(i=0; list[i]; i++) { + if(!strcmp(list[i], item)) + return i; + } + return -1; +} + +/* Take a char ** null terminated list of group names, and change a user's + * memberships so those are the only groups he's in. MLM */ +NSAPI_PUBLIC void change_user_membership(char *db_path, char *user, + char **new_groups) +{ + void *sortList; + int rv; + void *padb; + UserObj_t *uoptr = NULL; + GroupObj_t *goptr = NULL; + int groupCount=0; + register int i; + int index; + int id; + char *group; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) + report_error(SYSTEM_ERROR, db_path, + "Failed to open database while trying " + "to list groups."); + + sortList=_list_user_groups(padb, user, 0); + if(sortList) { + ulsSortName(sortList); + ulsGetCount(sortList, &groupCount); + } + + rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr); + if (uoptr == 0) { + report_error(INCORRECT_USAGE, user, "The user was not found."); + } + + /* First check the groups he's already in. Remove any that no longer + * appear in the list. */ + for(i=0; i<groupCount; ++i) { + ulsGetEntry(sortList, i, &id, &group); + + if( (index=_item_in_list(group, new_groups)) == -1) { + goptr=0; + rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr); + if (goptr == 0) { + report_error(INCORRECT_USAGE, group, + "The group was not found."); + } + rv = nsadbRemUserFromGroup(NULL, padb, goptr, uoptr); + } else { + /* This group is in the list, so mark it as taken care of. */ + if(new_groups) + new_groups[index][0]='\0'; + } + } + /* Add the user to any remaining groups. */ + if(new_groups) { + for(i=0; new_groups[i]; i++) { + if(new_groups[i][0] == '\0') + continue; + goptr=0; + rv = nsadbFindByName(NULL, padb, new_groups[i], + AIF_GROUP, (void **)&goptr); + if (goptr == 0) { + report_error(INCORRECT_USAGE, group,"The group was not found."); + } + rv = nsadbAddUserToGroup(NULL, padb, goptr, uoptr); + } + } + + nsadbClose(padb, 0); +} + +/* Take a char ** null terminated list of user names, and change a group's + * memberships so those are the only users it has. MLM */ +/* Again, if group_users is 1, then the new_users are assumed to be groups. */ +NSAPI_PUBLIC void change_group_membership(char *db_path, char *group, + int group_users, char **new_users) +{ + void *sortList; + int rv; + void *padb; + UserObj_t *uoptr = NULL; + GroupObj_t *goptr = NULL; + GroupObj_t *ugoptr = NULL; + int userCount=0; + register int i; + int index; + int id; + char *user; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) + report_error(SYSTEM_ERROR, db_path, + "Failed to open database while trying " + "to list groups."); + + sortList=_list_group_users(padb, group, group_users); + if(sortList) { + ulsSortName(sortList); + ulsGetCount(sortList, &userCount); + } + + rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr); + if (goptr == 0) { + report_error(INCORRECT_USAGE, group, "The group was not found."); + } + + /* First check the users already there. Remove any that no longer + * appear in the list. */ + for(i=0; i<userCount; ++i) { + ulsGetEntry(sortList, i, &id, &user); + if( (index=_item_in_list(user, new_users)) == -1) { + if(group_users) { + ugoptr=0; + rv = nsadbFindByName(NULL, padb, user, AIF_GROUP, + (void **)&ugoptr); + if (ugoptr == 0) { + report_error(INCORRECT_USAGE, user, + "The group was not found."); + } + rv = nsadbRemGroupFromGroup(NULL, padb, goptr, ugoptr); + } else { + uoptr=0; + rv = nsadbFindByName(NULL, padb, user, AIF_USER, + (void **)&uoptr); + if (uoptr == 0) { + report_error(INCORRECT_USAGE, user, + "The user was not found."); + } + rv = nsadbRemUserFromGroup(NULL, padb, goptr, uoptr); + } + } else { + /* This user is in the list, so mark it as taken care of. */ + if(new_users) + new_users[index][0]='\0'; + } + } + /* Add any remaining users. */ + if(new_users) { + for(i=0; new_users[i]; i++) { + if(new_users[i][0] == '\0') + continue; + if(group_users) { + ugoptr=0; + rv = nsadbFindByName(NULL, padb, new_users[i], + AIF_GROUP, (void **)&ugoptr); + if (ugoptr == 0) { + report_error(INCORRECT_USAGE, new_users[i], + "The group was not found."); + } + rv = nsadbAddGroupToGroup(NULL, padb, goptr, ugoptr); + if(rv) report_error(SYSTEM_ERROR, new_users[i], + "Unable to add group to group"); + } else { + uoptr=0; + rv = nsadbFindByName(NULL, padb, new_users[i], + AIF_USER, (void **)&uoptr); + if (uoptr == 0) { + report_error(INCORRECT_USAGE, new_users[i], + "The user was not found."); + } + rv = nsadbAddUserToGroup(NULL, padb, goptr, uoptr); + if(rv) report_error(SYSTEM_ERROR, new_users[i], + "Unable to add user to group"); + } + } + } + + nsadbClose(padb, 0); +} + +/* + * output a table with the groups that aren't members of the group + */ +NSAPI_PUBLIC void output_nongrpgroup_membership(char *db_path, char *group, char *filter) +{ + int rv; + GroupObj_t *goptr = 0; + void *padb; + USI_t *gidlist; + int i; + int id; + char *memgroup; + int groupCount; + char line[BIG_LINE]; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) { + report_error(SYSTEM_ERROR, db_path, + "Failed to open database while trying " + "to list group membership."); + } else { + rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr); + if (goptr == 0) { + report_error(SYSTEM_ERROR, group, + "Unable to find group when trying to " + "list group membership."); + rv = 1; + nsadbClose(padb, 0); + } else { + void *sortList; + + printf("<table border=1><caption align=left>\n"); + printf("<b>These groups are not members of %s:</b>", group); + printf("</caption>\n"); + + ulsAlloc(&sortList); + rv = nsadbEnumerateGroups(NULL, + padb, (void *)sortList, groupEnumCB); + nsadbClose(padb, 0); + ulsSortName(sortList); + ulsGetCount(sortList, &groupCount); + + if (groupCount > 0) { + gidlist = UILLIST(&goptr->go_groups); + for (i=0; i<groupCount; ++i) { + memgroup = NULL; + ulsGetEntry(sortList, i, &id, &memgroup); + if ( memgroup && + strcmp(memgroup, group) && + !idfound(id, (int*)gidlist, UILCOUNT(&goptr->go_groups)) && + passfilter(memgroup, filter)) { + printf("<tr>"); + printf("<td><b>%s</b></td><td>", memgroup); + sprintf(line, "group=%s", memgroup); + output_cgi_link("Edit Group", "grped", line); + printf("</td><td>"); + sprintf(line, "addtogrp_but=1&memgroup=%s&group=%s", + memgroup, group); + output_cgi_link("Add to Group", "grped", line); + printf("</td>\n"); + } + } + printf("</table>\n"); + } + ulsFree(&sortList); + groupFree(goptr); + } + } + return; +} + +/* + * output a table with the users that aren't members of the group + */ +NSAPI_PUBLIC void output_nonuser_membership(char *db_path, char *group, char *filter) +{ + int rv; + GroupObj_t *goptr = 0; + void *padb; + USI_t *gidlist; + int i; + int id; + char *memuser; + int userCount; + char line[BIG_LINE]; + + rv = nsadbOpen(NULL, db_path, 0, &padb); + if (rv < 0) { + report_error(SYSTEM_ERROR, db_path, + "Failed to open database while trying " + "to list group membership."); + } else { + rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr); + if (goptr == 0) { + nsadbClose(padb, 0); + report_error(SYSTEM_ERROR, group, + "Unable to find group when trying to " + "list user membership."); + rv = 1; + } else { + void *sortList; + + printf("<table border=1><caption align=left>\n"); + printf("<b>These users are not members of %s:</b>", group); + printf("</caption>\n"); + + ulsAlloc(&sortList); + rv = nsadbEnumerateUsers(NULL, padb, (void *)sortList, userEnumCB); + nsadbClose(padb, 0); + + ulsSortName(sortList); + ulsGetCount(sortList, &userCount); + + if (userCount > 0) { + gidlist = UILLIST(&goptr->go_users); + for (i=0; i<userCount; ++i) { + memuser = NULL; + ulsGetEntry(sortList, i, &id, &memuser); + if ( memuser && + !idfound(id, (int*)gidlist, UILCOUNT(&goptr->go_users)) && + passfilter(memuser, filter)) { + printf("<tr>"); + printf("<td><b>%s</b></td><td>", memuser); + sprintf(line, "memuser=%s", memuser); + output_cgi_link("Edit User", "usred", line); + printf("</td><td>"); + sprintf(line, "addtogrp_but=1&memuser=%s&group=%s", + memuser, group); + output_cgi_link("Add to Group", "grped", line); + printf("</td>\n"); + } + } + printf("</table>\n"); + } + ulsFree(&sortList); + groupFree(goptr); + } + } + return; +} + +NSAPI_PUBLIC char *get_acl_file() +{ + char line[BIG_LINE]; + char *acl_file = get_mag_var("ACLFile"); + if (!acl_file) { + sprintf(line, "%s%cgenerated.%s.acl", + get_httpacl_dir(), FILE_PATHSEP, get_srvname(0)); + set_mag_var("ACLFile", line); + acl_file = STRDUP(line); + } + if(!file_exists(acl_file)) { + FILE *f; + if(! (f=fopen(acl_file, "w")) ) + report_error(FILE_ERROR, acl_file, "Could not open file."); + fclose(f); + } + return acl_file; +} + +NSAPI_PUBLIC char *get_workacl_file() +{ + char line[BIG_LINE]; + char *workacl_file; + sprintf(line, "%s%cgenwork.%s.acl", + get_httpacl_dir(), FILE_PATHSEP, get_srvname(0)); + workacl_file = STRDUP(line); + + if(!file_exists(workacl_file)) { + FILE *f; + char *current=get_acl_file(); + if(file_exists(current)) { + cp_file(current, workacl_file, 0644); + } else { + if(! (f=fopen(workacl_file, "w")) ) + report_error(FILE_ERROR, workacl_file, "Could not open file."); + fclose(f); + } + } + return workacl_file; +} + +/* + * get_acl_info - Open the specified ACL file. Return a context + * handle into it, the data it contains, and whether this is + * a default allow or default deny resource. + * + * Returns: 0 if it works + * AUTHDB_ACL_FAIL (-1) if it fails + * AUTHDB_ACL_ODD_ACL (-2) if the ACL doesn't appear to be one + * generated by the CGI. + */ +NSAPI_PUBLIC int get_acl_info(char *acl_file, char *acl_name, void **pacl, + char ***hosts, authInfo_t **authinfo, + char ***users, char ***userhosts, + int *fdefaultallow) +{ + int rv = 0; + char *acl_sig = NULL; + ACContext_t *acl_con = NULL; + ACL_t *acl; + + if (hosts) + *hosts = NULL; + if (authinfo) + *authinfo = NULL; + if (users) + *users = NULL; + if (userhosts) + *userhosts = NULL; + if (fdefaultallow) + *fdefaultallow = 0; + + if ((rv = accReadFile(NULL, acl_file, &acl_con))) + rv = AUTHDB_ACL_FAIL; + else if (!(rv = aclFindByName(acl_con, acl_name, NULL, 0, &acl))) + rv = AUTHDB_ACL_NOT_FOUND; + else { + /* + * If we get the ACL open, get it's signiture to see if + * it looks like one of ours. Each directive is identified + * by a single character in the signiture string. The ones + * we care about are: + * 'a' - default allow + * 'd' - default deny + * 'r' - default authenticate + * + * The ACL used for default allow access has these directives: + * default allow anyone at *; (required, shows up as an 'a') + * default deny anyone at (hosts); (optional, shows up as a 'd') + * + * The ACL used for default deny access has these directives: + * default deny anyone at *; (required, shows up as an 'd') + * default allow anyone at (hosts); (optional, shows up as a 'a') + * default authenticate... (optional, shows up as an 'r') + * default allow (users) at (hosts); (optional, shows up as a 'a') + * + * Valid signitures are: + * "a" + * "ad" + * "d" + * "da" + * "dra" + * "dara" + */ + + if (acl) + acl_sig = aclGetSignature(acl); + + if (acl_sig) { + if (!strcmp(acl_sig, "a")) { + if (fdefaultallow) + *fdefaultallow = 1; + rv = 0; + } + else if (!strcmp(acl_sig, "ad")) { + if (fdefaultallow) + *fdefaultallow = 1; + if (hosts) + *hosts = aclGetHosts(acl, 2, 1); + rv = 0; + } + else if (!strcmp(acl_sig, "d")) { + if (fdefaultallow) + *fdefaultallow = 0; + rv = 0; + } + else if (!strcmp(acl_sig, "da")) { + if (fdefaultallow) + *fdefaultallow = 0; + if (hosts) + *hosts = aclGetHosts(acl, 2, 1); + rv = 0; + } + else if (!strcmp(acl_sig, "dra")) { + if (fdefaultallow) + *fdefaultallow = 0; + if (authinfo) { + char *p; + *authinfo = (authInfo_t *)MALLOC(sizeof(authInfo_t)); + memset(*authinfo, 0, (sizeof(authInfo_t))); + if ((p = aclGetAuthMethod(acl, 2))) + (*authinfo)->type = strdup(p); + if ((p = aclGetDatabase(acl, 2))) + (*authinfo)->db_path = strdup(p); + if ((p = aclGetPrompt(acl, 2))) + (*authinfo)->prompt = strdup(p); + } + if (users) + *users = aclGetUsers(acl, 3, 1); + if (userhosts) + *userhosts = aclGetHosts(acl, 3, 1); + rv = 0; + } + else if (!strcmp(acl_sig, "dara")) { + if (fdefaultallow) + *fdefaultallow = 0; + if (hosts) + *hosts = aclGetHosts(acl, 2, 1); + if (authinfo) { + char *p; + *authinfo = (authInfo_t *)MALLOC(sizeof(authInfo_t)); + memset(*authinfo, 0, (sizeof(authInfo_t))); + if ((p = aclGetAuthMethod(acl, 3))) + (*authinfo)->type = strdup(p); + if ((p = aclGetDatabase(acl, 3))) + (*authinfo)->db_path = strdup(p); + if ((p = aclGetPrompt(acl, 3))) + (*authinfo)->prompt = strdup(p); + } + if (users) + *users = aclGetUsers(acl, 4, 1); + if (userhosts) + *userhosts = aclGetHosts(acl, 4, 1); + rv = 0; + } + else + rv = AUTHDB_ACL_ODD_ACL; + } + if (pacl) + *pacl = (void *)acl_con; + } + return rv; +} + + +static void add_acl_rights(ACContext_t *acc) +{ + int rv; + char **p; + for (p = acl_read_rights; *p; ++p) { + rv = aclRightDef(NULL, acc, *p, NULL); + } + for (p = acl_write_rights; *p; ++p) { + rv = aclRightDef(NULL, acc, *p, NULL); + } +} + +/* + * delete_acl_by_name - remove a specified acl. + * + * Return: 0 if it deletes an ACL. Otherwise something else. + * + */ +NSAPI_PUBLIC int delete_acl_by_name(char *acl_file, char *acl_name) +{ + int rv = 1; + ACContext_t *acl_con = NULL; + ACL_t *acl = NULL; + + if (acl_file && acl_name) + { + rv = accReadFile(NULL, acl_file, &acl_con); + + if (!rv) { + rv = aclFindByName(acl_con, acl_name, NULL, 0, &acl); + if (rv == 1 && acl) { + aclDelete(acl); + rv = accWriteFile(acl_con, acl_file, 0); + set_commit(0, 1); + } + } + } + return rv; +} + +/* + * set_acl_info - Replaces the specified ACL with the information + * provided. The fdefaultallow is tells us whether + * to generate a default allow everyone type ACL, or + * a default deny everyone type ACL. + * + * If opening the ACL file fails with a file open + * type error, it is assumed to not exist, and a + * new one is created. + * + * Returns: 0 if it works + * AUTHDB_ACL_FAIL if it fails + */ +NSAPI_PUBLIC int set_acl_info(char *acl_file, char *acl_name, int prefix, + void **pacl, char **rights, + char **hosts, authInfo_t *authinfo, + char **users, char **userhosts, + int fdefaultallow) +{ + int rv = AUTHDB_ACL_FAIL; + ACContext_t *acl_con = NULL; + ACL_t *acl = NULL; + int amethod = AUTH_METHOD_BASIC; + char *db_path = NULL; + char *prompt = NULL; + + /* + * Digest parms + */ + if (authinfo) { + if (!strcmp(authinfo->type, "SSL")) + amethod = AUTH_METHOD_SSL; + else + amethod = AUTH_METHOD_BASIC; + db_path = authinfo->db_path; + prompt = authinfo->prompt; + } + + if (prefix) + prefix = ACLF_NPREFIX; + else + prefix = 0; + + /* + * Open the specified ACL file, destroy the existing ACL with + * the specified name if it exists, and then write the new + * stuff back out. + */ + if (acl_file && acl_name) + { + (void)delete_acl_by_name(acl_file, acl_name); + rv = accReadFile(NULL, acl_file, &acl_con); + + /* + * If the file isn't there, create an empty context. + */ + if (rv == ACLERROPEN) + rv = accCreate(0, 0, &acl_con); + + if (rv) + rv = AUTHDB_ACL_FAIL; + else { + (void)add_acl_rights(acl_con); + + if (aclMakeNew(acl_con, "", acl_name, + rights, prefix, &acl)) { + rv = AUTHDB_ACL_FAIL; + } + else if (aclPutAllowDeny( + NULL, acl, 0, fdefaultallow, NULL, NULL)) { + rv = AUTHDB_ACL_FAIL; + } + else if (hosts && + (rv = aclPutAllowDeny( + NULL, acl, 0, !fdefaultallow, NULL, hosts))) { + + rv = AUTHDB_ACL_FAIL; + } + else if (users && authinfo && + ((rv = aclPutAuth(NULL, acl, 0, amethod, db_path, prompt))|| + (rv = aclPutAllowDeny(NULL, acl, 0, !fdefaultallow, + users, userhosts)))) { + + rv = AUTHDB_ACL_FAIL; + } + else { + if (accWriteFile(acl_con, acl_file, 0)) { + rv = AUTHDB_ACL_FAIL; + } + else { + set_commit(0, 1); + rv = 0; + if (pacl) + *pacl = (void *)acl; + } + } + } + } + return rv; +} + +/* + * get_acl_names - Passes back the names of the read and write + * ACLs for the current resource. + * The directive parm is usually "acl", but is + * also used to find stashed items under names + * like "acl-disabled". + * Returns 0 if no other ACLs are found, 1 if an ACL that + * doesn't match the type of name we generate. + */ +NSAPI_PUBLIC int get_acl_names(char **readaclname, char **writeaclname, char *directive) +{ + pblock **pbs; + char *aclname; + int fother_acls = 0; + char **config = get_adm_config(); + char *curres = get_current_resource(config); + int rtype = get_current_restype(config); + int i; + + *readaclname = NULL; + *writeaclname = NULL; + + pbs = list_pblocks(rtype, curres, "PathCheck", CHECK_ACL_FN); + + if (pbs) { + for (i=0; pbs[i]; ++i) { + aclname = pblock_findval(directive, pbs[i]); + if (is_readacl(aclname)) + *readaclname = strdup(aclname); + else if (is_writeacl(aclname)) + *writeaclname = strdup(aclname); + else + fother_acls = 1; + } + } + return fother_acls; +} + +NSAPI_PUBLIC int is_readacl(char *name) { + if (name) + return strstr(name, ACLNAME_READ_COOKIE)?1:0; + else + return 0; +} + +NSAPI_PUBLIC int is_writeacl(char *name) { + if (name) + return strstr(name, ACLNAME_WRITE_COOKIE)?1:0; + else + return 0; +} + +NSAPI_PUBLIC int admin_is_ipaddr(char *p) +{ + int i; + int num_found = 0; + + if (!p || !p[0]) + return 0; /* NULL isn't an IP Address */ + else { + for (i=0; p[i]; ++i) { + if (isalpha(p[i])) + return 0; /* If it has an alpha character, it's not IP addr */ + else if (isdigit(p[i])) { + num_found = 1; + } + } + } + /* + * Well, hard to say what it is, but if there's at least a number + * in it, and the ip number checker can parse it, we'll call it + * an IP address; + */ + if (num_found && get_ip_and_mask(p)) + return 1; + else + return 0; +} + +/* + * Get the hostnames and ipaddrs strings from the single hosts array + * of string pointers. + */ +NSAPI_PUBLIC void get_hostnames_and_ipaddrs(char **hosts, char **hostnames, char **ipaddrs) +{ + char *p; + int nbipaddrs = 0; + int nbhostnames = 0; + int i; + if (hosts && hostnames && ipaddrs) { + *hostnames = NULL; + *ipaddrs = NULL; + /* + * Make two passes, once to total the size needed for + * the hosts and ipaddrs string, then alloc them and + * strcat the strings in. + */ + for(i=0, p=hosts[i]; p; p=hosts[++i]) { + if (admin_is_ipaddr(p)) + nbipaddrs += strlen(p) + 2; /* Teminator and "," */ + else + nbhostnames += strlen(p) + 2; + } + + if (nbhostnames) { + *hostnames = (char *)MALLOC(nbhostnames + 1); + memset(*hostnames, 0, nbhostnames); + } + if (nbipaddrs) { + *ipaddrs = (char *)MALLOC(nbipaddrs + 1); + memset(*ipaddrs, 0, nbipaddrs); + } + + /* + * We've got the space, now go look at each, strcat it + * into the correct string, prefixed with a "," for all + * but the first. + */ + for(i=0, p=hosts[i]; p; p=hosts[++i]) { + if (admin_is_ipaddr(p)) { + if (strlen(*ipaddrs)) + strcat(*ipaddrs, ","); + strcat(*ipaddrs, p); + } + else { + if (strlen(*hostnames)) + strcat(*hostnames, ","); + strcat(*hostnames, p); + } + } + } + return; +} + +/* + * Get the usernames and groups strings from the single users array + * of string pointers. + */ +NSAPI_PUBLIC void get_users_and_groups(char **users, char **usernames, char **groups, + char *db_path) +{ + char *p; + int nbusernames = 0; + int nbgroups = 0; + int i; + int is_user = 0; + int is_group = 0; + + if (users && usernames && groups) { + *usernames = NULL; + *groups = NULL; + /* + * Make two passes, once to total the size needed for + * the strings, then alloc them and strcat the strings in. + */ + for(i=0, p=users[i]; p; p=users[++i]) { + is_user = 0; + is_group = 0; + groupOrUser(db_path, p, &is_user, &is_group); + + /* Enclose user/group name in quotes if necessary */ + p = aclSafeIdent(p); + + if (is_user) + nbusernames += strlen(p) + 2; /* Teminator and "," */ + else if (is_group) + nbgroups += strlen(p) + 2; + } + + if (nbusernames) { + *usernames = (char *)MALLOC(nbusernames + 1); + memset(*usernames, 0, nbusernames); + } + if (nbgroups) { + *groups = (char *)MALLOC(nbgroups + 1); + memset(*groups, 0, nbgroups); + } + + /* + * We've got the space, now go look at each, strcat it + * into the correct string, prefixed with a "," for all + * but the first. + */ + for(i=0, p=users[i]; p; p=users[++i]) { + is_user = 0; + is_group = 0; + groupOrUser(db_path, p, &is_user, &is_group); + + /* Enclose user/group name in quotes if necessary */ + p = aclSafeIdent(p); + + if (is_user) { + if (strlen(*usernames)) + strcat(*usernames, ","); + strcat(*usernames, p); + } + else if (is_group) { + if (strlen(*groups)) + strcat(*groups, ","); + strcat(*groups, p); + } + } + } + return; +} + +/* + * Load from host and IP Addr strings into the array of + * pointers to strings. + */ +NSAPI_PUBLIC void load_host_array(char ***hosts, char *hostnames, char *ipaddrs) +{ + char *tok; + int nMax = 20; + int nCur = 0; + char **hostarr; + char *valid_ip; + + if (hosts) { + hostarr = new_strlist(nMax); + hostarr[0] = NULL; + if (hostnames) { + for (tok = strtok(hostnames, ","); + tok; + tok = strtok(NULL, ",")) + { + if (!(nCur < nMax)) { + nMax += 20; + hostarr = grow_strlist(hostarr, nMax); + } + hostarr[nCur] = strdup(tok); + hostarr[++nCur] = NULL; + } + } + if (ipaddrs) { + for (tok = strtok(ipaddrs, ","); + tok; + tok = strtok(NULL, ",")) + { + if (!(nCur < nMax)) { + nMax += 20; + hostarr = grow_strlist(hostarr, nMax); + } + valid_ip = get_ip_and_mask(tok); + if (valid_ip) { + hostarr[nCur] = strdup(valid_ip); + hostarr[++nCur] = NULL; + } + } + } + *hosts = hostarr; + } + + return; +} + +void load_users_array(char ***users, char *usernames, char *groups) +{ + char *tok; + int nMax = 20; + int nCur = 0; + char **userarr; + + if (users) { + userarr = new_strlist(nMax); + userarr[0] = NULL; + if (usernames) { + for (tok = strtok(usernames, ","); + tok; + tok = strtok(NULL, ",")) + { + if (!(nCur < nMax)) { + nMax += 20; + userarr = grow_strlist(userarr, nMax); + } + userarr[nCur] = strdup(tok); + userarr[++nCur] = NULL; + } + } + if (groups) { + for (tok = strtok(groups, ","); + tok; + tok = strtok(NULL, ",")) + { + if (!(nCur < nMax)) { + nMax += 20; + userarr = grow_strlist(userarr, nMax); + } + userarr[nCur] = strdup(tok); + userarr[++nCur] = NULL; + } + } + *users = userarr; + } + + return; +} + +/* Removes enclosing double quotes from a string (in place) */ +NSAPI_PUBLIC char * str_unquote(char * str) +{ + if (str) { + if (str[0] == '"') { + int len = strlen(str); + + if (str[len-1] == '"') { + str[len-1] = 0; + ++str; + } + } + } + + return str; +} diff --git a/lib/libadmin/error.c b/lib/libadmin/error.c new file mode 100644 index 00000000..a4f87842 --- /dev/null +++ b/lib/libadmin/error.c @@ -0,0 +1,109 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * error.c - Handle error recovery + * + * All blame to Mike McCool + */ + +#include "libadmin/libadmin.h" +#if 0 +#include "cgiutils/cgi-util.h" +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef XP_WIN32 +#include <windows.h> +#include "base/nterr.h" +#endif + +#define ERROR_HTML "error.html" + +/* Be sure to edit libadmin.h and add new #define types for these headers. */ +char *error_headers[MAX_ERROR] = + {"File System Error", + "Memory Error", + "System Error", + "Incorrect Usage", + "Form Element Missing", + "Registry Database Error", + "Network Error", + "Unexpected Failure", + "Warning"}; + +#ifdef XP_UNIX +#define get_error() errno +#define verbose_error() system_errmsg() +#else /* XP_WIN32 */ +int get_error() +{ + int error = GetLastError(); + return(error ? error: WSAGetLastError()); +} +char *verbose_error() +{ + /* Initialize error hash tables */ + HashNtErrors(); + return alert_word_wrap(system_errmsg(), WORD_WRAP_WIDTH, "\\n"); +} +#endif /* XP_WIN32 */ + +void _report_error(int type, char *info, char *details, int shouldexit) +{ + /* Be sure headers are terminated. */ + fputs("\n", stdout); + + fprintf(stdout, "<SCRIPT LANGUAGE=\"%s\">", MOCHA_NAME); + output_alert(type, info, details, 0); + if(shouldexit) { + fprintf(stdout, "if(history.length>1) history.back();"); + } + fprintf(stdout, "</SCRIPT>\n"); + + if(shouldexit) { + WSACleanup(); + exit(0); + } +} + +/* + * Format and output a call to the JavaScript alert() function. + * The caller must ensure a JavaScript context. + */ +NSAPI_PUBLIC void output_alert(int type, char *info, char *details, int wait) +{ + char *wrapped=NULL; + int err; + + if(type >= MAX_ERROR) + type=DEFAULT_ERROR; + + wrapped=alert_word_wrap(details, WORD_WRAP_WIDTH, "\\n"); + + if(!info) info=""; + fprintf(stdout, (wait) ? "confirm(\"" : "alert(\""); + fprintf(stdout, "%s:%s\\n%s", error_headers[type], info, wrapped); + if(type==FILE_ERROR || type==SYSTEM_ERROR) { + err = get_error(); + if(err != 0) + fprintf(stdout, + "\\n\\nThe system returned error number %d, " + "which is %s.", err, verbose_error()); + } + fprintf(stdout, "\");"); +} + +NSAPI_PUBLIC void report_error(int type, char *info, char *details) +{ + _report_error(type, info, details, 1); +} + +NSAPI_PUBLIC void report_warning(int type, char *info, char *details) +{ + _report_error(type, info, details, 0); +} + diff --git a/lib/libadmin/strlist.c b/lib/libadmin/strlist.c new file mode 100644 index 00000000..46a0c600 --- /dev/null +++ b/lib/libadmin/strlist.c @@ -0,0 +1,46 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * strlist.c: Managing a handle to a list of strings + * + * All blame to Mike McCool + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "netsite.h" +#include <libadmin/libadmin.h> + +NSAPI_PUBLIC char **new_strlist(int size) +{ + char **new_list; + register int x; + + new_list = (char **) MALLOC((size+1)*(sizeof(char *))); +/* <= so we get the one right after the given size as well */ + for(x=0; x<= size; x++) + new_list[x] = NULL; + + return new_list; +} + +NSAPI_PUBLIC char **grow_strlist(char **strlist, int newsize) +{ + char **ans; + + ans = (char **) REALLOC(strlist, (newsize+1)*sizeof(char *)); + + return ans; +} + +NSAPI_PUBLIC void free_strlist(char **strlist) +{ + int x; + + for(x=0; (strlist[x]); x++) free(strlist[x]); + free(strlist); +} diff --git a/lib/libadmin/template.c b/lib/libadmin/template.c new file mode 100644 index 00000000..a689d3b5 --- /dev/null +++ b/lib/libadmin/template.c @@ -0,0 +1,820 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * template.c: The actual HTML templates in a static variable + * + * All blame to Mike McCool + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "template.h" +#include "libadmin/libadmin.h" +#include "libadmin/dbtlibadmin.h" +#include "base/util.h" + +/* If you add something to this structure, don't forget to document it + * in templates.h, and increase MAXTEMPLATE! + * + * Also, save yourself a lot of grief and put a space after the name. + */ + +static struct template_s templates[MAXTEMPLATE] = { + {"IF ", "FUNC conditional"}, + {"ELSE ", "FUNC conditional"}, + {"ENDIF ", "FUNC conditional"}, + {"TITLE ", "<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n" + "<BODY bgcolor=\"#C0C0C0\" link=\"#0000EE\" " + "vlink=\"#551A8B\" alink=\"#FF0000\" %s>\n"}, + {"PAGEHEADER ", "FUNC pageheader"}, + {"DOCSWITCHER ", ""}, + {"COPYRIGHT ", ""}, + {"RESOURCEPICKER ", "FUNC respicker"}, + {"BOOKTRACK ", "FUNC booktrack"}, + {"BEGININFO ", "<table border=2 width=100%% cellpadding=2>\n" + "<tr><td align=center colspan=2>" + "<b><FONT size=+1>%s</FONT></b></td></tr>" +#if 0 + "<tr><td>" + "<IMG src=\"../icons/b-open.gif\" hspace=8 alt=\"*\"" + "height=26 width=55></td>" + "<td>\n"}, +#endif + "<td colspan=2>\n"}, + {"ADDINFO ", "</td></tr><tr><td colspan=2>"}, + {"ENDINFO ", "</td></tr></table>\n<hr width=10%%>\n"}, + {"SUBMIT ", "FUNC submit\n"}, + {"DOCUMENTROOT ", "FUNC docroot"}, + {"BEGINELEM ", "<pre>"}, +/* {"ELEM ", "<hr width=100%%><b>%s</b>"}, */ + {"ELEM ", "\n<b>%s</b>"}, +/* {"ENDELEM ", "<hr width=100%%></pre>\n"}, */ + {"ENDELEM ", "</pre>\n"}, + {"ELEMADD ", "<b>%s</b>"}, +/* {"ELEMDIV ", "<hr width=100%%>"}, */ + {"ELEMDIV ", "\n"}, + {"REFERER ", "FUNC link_referer"}, + {"INDEX ", "<a href=\"index\">%s</a>\n"}, + {"SERVERROOT ", "FUNC serverroot"}, + {"RESTART ", "<a href=\"pcontrol\">%s</a>\n"}, + {"ACCESS ", "FUNC makeurl"}, + {"COMMIT ", "<a href=\"commit?commit\">%s</a>\n"}, + {"BACKOUT ", "<center>If you don't want to %s, you can <a href=index>" + "return to the server manager.</a></center>\n"}, + {"CURSERVNAME", "FUNC curservname"}, + {"VERIFY ", "FUNC verify"}, + {"HELPBUTTON", "FUNC helpbutton"}, + {"DIALOGSUBMIT", "FUNC dialogsubmit"}, + {"HELPJSFN", "FUNC helpjsfn"} +}; + +int get_directive(char *string); +void conditional(char *input, char **vars, int index); +void respicker(char **config); +void currentres(char **config); +void prevres(char **config); +void booktrack(char *input, char **vars); +void docswitcher(char *input); +void docroot(char **vars); +void link_referer(char **input, char **vars); +void serverroot(char **vars); +char **get_vars(char *string); +static void output(char *string); +void makeurl(char **vars); +void curservname(void); +void pageheader(char **vars, char **config); +void submit(int verify, char **vars); +void helpbutton(char *topic); +void dialogsubmit(char *topic); + +static int status = -1; + +/* Filter a page. Takes the page to filter as an argument. Uses above + * filters to process. + */ +NSAPI_PUBLIC int parse_line(char *line_input, char **input) +{ + register int index; + char *position; + int dirlen = strlen(DIRECTIVE_START); + char **vars; + + + if(!strncmp(line_input, DIRECTIVE_START, dirlen)) { + position = (char *) (line_input + dirlen); + index = get_directive(position); + + /* did we get one? */ + if(index != -1) { + /* if so, get the vars. */ + position += strlen(templates[index].name); + vars = get_vars(position); + /* Dispatch the correct function (done for readability, + * although I'm starting to wonder if I should bother) + */ + if(!strncmp(templates[index].format, "FUNC ", 5)) { + + if(!strncmp(templates[index].format+5, "conditional", 11)) + conditional(input[0], vars, index); + else if(!strncmp(templates[index].format+5, "respicker", 9)) + respicker(input); + else if(!strncmp(templates[index].format+5, "booktrack", 9)) + booktrack(input[0], vars); + else if(!strncmp(templates[index].format+5, "docswitcher", 11)) + docswitcher(input[0]); + else if(!strncmp(templates[index].format+5, "docroot", 7)) + docroot(vars); + else if(!strncmp(templates[index].format+5, "link_referer",12)) + link_referer(input, vars); + else if(!strncmp(templates[index].format+5, "serverroot",10)) + serverroot(vars); + else if(!strncmp(templates[index].format+5, "makeurl",7)) + makeurl(vars); + else if(!strncmp(templates[index].format+5, "curservname",11)) + curservname(); + else if(!strncmp(templates[index].format+5, "pageheader",10)) + pageheader(vars, input); + else if(!strncmp(templates[index].format+5, "submit",6)) + submit(0, vars); + else if(!strncmp(templates[index].format+5, "verify",6)) + submit(1, vars); + else if(!strncmp(templates[index].format+5, "helpbutton",10)) + helpbutton(vars[0]); + else if(!strncmp(templates[index].format+5, "dialogsubmit",12)) + dialogsubmit(vars[0]); + /* We don't know what this template is. Send it back. */ + else return -1; + } else { + /* I just can't believe there's no easy way to create + * a va_list. */ + char line[BIG_LINE]; + sprintf(line, templates[index].format, + (vars[0] != NULL) ? vars[0]: "", + (vars[1] != NULL) ? vars[1]: "", + (vars[2] != NULL) ? vars[2]: "", + (vars[3] != NULL) ? vars[3]: ""); + output(line); + } + } else { + /* We found a directive, but we can't identify it. Send it back.*/ + /* Check status first; if we're not supposed to be outputing */ + /* because of an "IF" block, don't tell the program to */ + /* try and cope with it. */ + if(status) + return -1; + else + return 0; + } + } else + /* We found no directive. The line is normal. */ + output(line_input); + + /* If we're here, we either handled it correctly or the line was benign.*/ + return 0; +} + +void conditional(char *input, char **vars, int index) +{ + if((!strncmp(templates[index].name, "IF", 2)) && + (vars[0] != NULL)) { + status = input[atoi(vars[0])] - '0'; + } else + if((!strncmp(templates[index].name, "ELSE", 4)) && + (status != -1)) { + status ^= 1; + } else + if(!strncmp(templates[index].name, "ENDIF", 5)) + status = -1; +} + +void respicker(char **config) +{ + output("<FORM action=rsrcpckr method=GET>\n"); + output("<hr size=4><center>\n"); + prevres(config); + output("</center><hr size=4>\n"); + output("</FORM>\n"); +} + +void currentres(char **config) +{ + int l; + char line[BIG_LINE]; + char *resname, *restype; + + resname = get_current_resource(config); + restype = get_current_typestr(config); + if(!strcmp(restype, NAME)) { + if(!strcmp(resname, "default")) + sprintf(line, "<font size=+1>Modifying: " + "<b>the entire server</b>.</font>"); + else + sprintf(line, "<font size=+1>Modifying: " + "<b>the object named %s</b>.</font>", resname); + } + else if(!strcmp(restype, FILE_OR_DIR)) { + l = strlen(resname) - 1; + if(resname[l] == '*') { + sprintf(line, "<font size=+1>Modifying: <b>the directory " + "%s</b></font>", + resname); + } else { + sprintf(line, "<font size=+1>Modifying: <b>%s %s</b></font>", + (strchr(resname, '*')) ? "files matching" : "the file", + resname); + } + } + else if(!strcmp(restype, TEMPLATE)) { + sprintf(line, "<font size=+1>Modifying: <b>the template %s</b></font>", + resname); + } + else if(!strcmp(restype, WILDCARD)) { +#ifdef MCC_PROXY + sprintf(line, "<font size=+1>Modifying: <b>URLs matching RE %s" +#else + sprintf(line, "<font size=+1>Modifying: <b>files matching %s" +#endif + "</b></font>", + resname); + } + output(line); +} + +void prevres(char **config) +{ +#ifndef MCC_NEWS + char *res = get_current_resource(config); + int rtype = get_current_restype(config); + + if(status) { + char **options = NULL; + register int x=0; + int found=0; + int option_cnt = total_object_count(); + + fprintf(stdout, "<SCRIPT language=JavaScript>\n"); + fprintf(stdout, "function checkForClick() {\n"); + fprintf(stdout, " document.forms[0].resource.blur();\n"); + fprintf(stdout, " var idx=document.forms[0]." + "resource.options.selectedIndex;\n"); + fprintf(stdout, " if(document.forms[0].resource." + "options[idx].defaultSelected == 0) {\n"); + fprintf(stdout, " document.forms[0].submit();\n"); + fprintf(stdout, " return 1;\n"); + fprintf(stdout, " } else return 0;\n"); + fprintf(stdout, "}\n"); + fprintf(stdout, "</SCRIPT>\n"); + +#ifdef MCC_PROXY + fprintf(stdout, "<TABLE BORDER=0>\n"); + fprintf(stdout, "<TR><TD><font size=+1>Editing:</font></TD>\n"); + fprintf(stdout, + "<TD><SELECT name=\"resource\" onChange=\"checkForClick()\" SIZE=\"%d\">\n", + option_cnt <= 20 ? 1 : 5); +#else + output("<nobr>"); + fputs("<font size=+1>Editing:</font>\n", stdout); + fprintf(stdout, "<SELECT name=\"resource\" " + "onChange=\"checkForClick()\" %s>\n", + option_cnt <=20 ? "" : "size=5"); +#endif + +#ifdef MCC_HTTPD /* template->styles nightmare */ + if((rtype==PB_NAME) && (strcmp(res, "default"))) { + /* enter: STYLES MODE */ + fprintf(stdout, "<OPTION value=ndefault>Exit styles mode\n"); + } else { + fprintf(stdout, "<OPTION value=ndefault %s>The entire server\n", + (!strcmp(res, "default")) ? "SELECTED" : ""); + } +#else + fprintf(stdout, "<OPTION value=ndefault %s>The entire server\n", + (!strcmp(res, "default")) ? "SELECTED" : ""); +#endif + if(!strcmp(res, "default")) found=1; + options = list_objects(PB_PATH); +#ifdef MCC_HTTPD /* template->styles nightmare */ + if((options) && !((rtype==PB_NAME) && (strcmp(res, "default"))) ) { +#else + if(options) { +#endif + for(x=0; options[x]; x++) { + fprintf(stdout, "<OPTION value=f%s %s>%s\n", + options[x], + (!strcmp(options[x], res)) ? "SELECTED" : "", + options[x]); + if(!strcmp(options[x], res)) found=1; + } + } + options=list_objects(PB_NAME); +#ifdef MCC_HTTPD /* template->styles nightmare */ + if((options) && ((rtype==PB_NAME) && (strcmp(res, "default"))) ) { +#else + if(options) { +#endif + for(x=0; options[x]; x++) { + if(!strcmp(options[x], "default") || + !strcmp(options[x], "cgi")) + continue; +#ifdef MCC_HTTPD /* template->style usability */ + fprintf(stdout, "<OPTION value=n%s %s>The style '%s'\n", + options[x], + (!strcmp(options[x], res)) ? "SELECTED":"", + options[x]); +#else + fprintf(stdout, "<OPTION value=n%s %s>The template '%s'\n", + options[x], + (!strcmp(options[x], res)) ? "SELECTED":"", + options[x]); +#endif + if(!strcmp(options[x], res)) found=1; + } + } + if(!found) { + if(rtype==PB_NAME) { + fprintf(stdout, "<OPTION value=n%s SELECTED>The template %s\n", + res, res); + } else { + fprintf(stdout, "<OPTION value=f%s SELECTED>%s\n", + res, res); + } + } + fputs("</SELECT></nobr>\n", stdout); + fputs("<nobr>", stdout); +#ifndef MCC_PROXY + fprintf(stdout, "<INPUT type=button value=\"Browse...\" " + "onClick=\"window.location='rsrcpckr?b'\"> "); +#endif +#ifdef MCC_PROXY + fprintf(stdout, "</TD>\n<TD>"); + fprintf(stdout, "<INPUT type=button value=\"Regular Expression...\" " + "onClick=\"var pat=" + "prompt('Enter the regular expression to edit:', ''); " +#else + fprintf(stdout, "<INPUT type=button value=\"Wildcard...\" " + "onClick=\"var pat=" + "prompt('Enter the wildcard pattern to edit:', ''); " +#endif + "if(pat!=null) window.location='rsrcpckr?" + "type="WILDCARD"&resource='+escape(pat);\">"); +#ifdef MCC_PROXY + fprintf(stdout, "</TD>\n</TR>\n</TABLE>\n"); +#endif + fputs("</nobr>", stdout); + /* output("</td></tr>\n"); */ + } +#endif +} + +void booktrack(char *input, char **vars) +{ + char line[BIG_LINE]; + + if((vars[0] != NULL) && (vars[1] != NULL)) { + sprintf(line, "<a href=index?0>" + "<img src=\"%s\" hspace=8 align=%s alt=\"\"></a>", + (input[0] - '0') ? vars[0] : vars[1], + (vars[2] != NULL) ? vars[2] : "none"); + output(line); + } +} + +void docswitcher(char *input) +{ + char line[BIG_LINE]; + char *whichimg, *whatmode; +#ifdef USE_ADMSERV + char *qs = getenv("QUERY_STRING"); + char *sname = getenv("SCRIPT_NAME"); + char *mtmp; + + char *tmp = getenv("SERVER_NAMES"); + char *servers = NULL; + if(tmp) servers = STRDUP(tmp); +#endif + + if(!(input[0] - '0')) { + whichimg = "b-clsd.gif"; + whatmode = "Express mode"; + } else { + whichimg = "b-open.gif"; + whatmode = "Full docs"; + } + + mtmp = (char *) MALLOC( (sname? strlen(sname) : 0) + + (qs? strlen(qs) : 0) + + (strlen(whichimg) + strlen(whatmode)) + + 1024); + sprintf(mtmp, "<center><table border=2 width=95%%>\n" + "<tr><td rowspan=2><a href=index%s>" + "<img src=\"../icons/%s\" " + "alt=\"[%s] \" border=2>" + "</td>\n", + (qs ? "?0" : sname), + whichimg, whatmode); + output(mtmp); + +#ifdef USE_ADMSERV + if(!servers) { + sprintf(line, "<td width=100%% align=center rowspan=2><b>%s</b></td>\n", + whatmode); + output(line); + } else + if(servers[0] == '(') { + + sprintf(line, "<td width=100%% align=center>Current servers:<br>\n"); + output(line); + output("<b>"); + + tmp=strtok(++servers, "|)"); + while(tmp) { + char *tmp2; + output("<nobr>"); + tmp2=strchr(tmp, '-'); + tmp2++; + output(tmp2); + tmp=strtok(NULL, "|)"); + if(tmp) + output(","); + output("</nobr>\n"); + } + output("</b></td>\n"); + } else { + + sprintf(line, "<td width=100%% align=center>Current server: "); + output(line); + output("<b>"); + tmp = strchr(servers, '-'); + *tmp++ = '\0'; + output(tmp); + output("</b>"); + output("</td>\n"); + } +#endif + sprintf(mtmp, "<td rowspan=2><a href=index%s>" + "<img src=\"../icons/%s\" " + "alt=\"\" border=2></a></td></tr>\n", + (qs? "?0" : sname), + whichimg); + output(mtmp); +#ifdef USE_ADMSERV + if(servers) { + sprintf(line, "<tr><td align=center>" + "<a href=\"/admin-serv/bin/chooser\">" + "Choose</a> a new server or set of servers</a></td>\n"); + output(line); + } +#endif + sprintf(line, "</tr></table></center>\n"); + output(line); + output("<hr width=10%%>\n"); +} + +void docroot(char **vars) +{ +#ifndef MCC_NEWS + char line[BIG_LINE]; + pblock *pb = grab_pblock(PB_NAME, "default", "NameTrans", "document-root", + NULL, NULL); + char *docroot = ""; + if(pb) + docroot = pblock_findval("root", pb); + sprintf(line, "<b>%s%s</b>\n", docroot, (vars[0] != NULL) ? vars[0] : ""); + output(line); +#endif +} + +void serverroot(char **vars) +{ + char line[BIG_LINE]; +#ifdef USE_ADMSERV + char *sroot = getenv("NETSITE_ROOT"); +#else + char *sroot = get_mag_var("#ServerRoot"); +#endif + sprintf(line, "%s%s", (sroot) ? sroot : "", (vars[0]) ? vars[0] : ""); + output(line); +} + +void makeurl(char **vars) +{ + char line[BIG_LINE]; + + sprintf(line,"<a href=%s target=_blank>%s</a>\n", + get_serv_url(), vars[0] ? vars[0] : ""); + output(line); +} + +void curservname(void) +{ + output(get_srvname(0)); +} + +NSAPI_PUBLIC +void pageheader(char **vars, char **config) +{ + char line[BIG_LINE]; +#if 0 /* MLM - put in to have non-working Back button */ + char *ref=get_referer(config); + char *t; +#endif + + output("<center><table border=2 width=100%%>\n"); + + util_snprintf(line, BIG_LINE, "<tr>"); + output(line); + + util_snprintf(line, BIG_LINE, "<td align=center width=100%%>"); + output(line); + util_snprintf(line, BIG_LINE, "<hr size=0 width=0>"); + output(line); +#if 0 /* MLM - put in to have non-working Back button */ + t=strrchr(ref, '/'); + *t++='\0'; + util_snprintf(line, BIG_LINE, "<a href=\"%s/index/%s\">", ref, t); + output(line); + util_snprintf(line, BIG_LINE, "<img align=right src=../icons/back.gif " + "width=41 height=26 border=0></a>\n"); + output(line); +#endif + util_snprintf(line, BIG_LINE, "<FONT size=+2><b>%s</b></FONT>" + "<hr size=0 width=0>" + "</td>", vars[2]); + output(line); + + output("</tr></table></center>\n"); +} + +char *_get_help_button(char *topic) +{ + char line[BIG_LINE]; + + util_snprintf( line, BIG_LINE, + "<input type=button value=\"%s\" " + "onClick=\"%s\">", XP_GetAdminStr(DBT_help_), + topic ? helpJavaScriptForTopic( topic ) : helpJavaScript() ); + + return(STRDUP(line)); +} + +NSAPI_PUBLIC char *helpJavaScriptForTopic( char *topic ) +{ + char *tmp; + char line[BIG_LINE]; + char *server=get_srvname(0); + char *type; + int typeLen; + + /* Get the server type, without the instance name into type */ + tmp = strchr( server, '-' ); + typeLen = tmp - server; + + type = (char *)MALLOC( typeLen + 1 ); + type[typeLen] = '\0'; + while ( typeLen-- ) { + type[typeLen] = server[typeLen]; + } + util_snprintf( line, BIG_LINE, + "if ( top.helpwin ) {" + " top.helpwin.focus();" + " top.helpwin.infotopic.location='%s/%s/admin/tutor?!%s';" + "} else {" + " window.open('%s/%s/admin/tutor?%s', '" + INFO_IDX_NAME"_%s', " + HELP_WIN_OPTIONS");}", + getenv("SERVER_URL"), server, topic, + getenv("SERVER_URL"), server, topic, + type ); + + return(STRDUP(line)); +} + +NSAPI_PUBLIC char *helpJavaScript() +{ + char *tmp, *sn; + + tmp=STRDUP(getenv("SCRIPT_NAME")); + if(strlen(tmp) > (unsigned)BIG_LINE) + tmp[BIG_LINE-2]='\0'; + sn=strrchr(tmp, '/'); + if( sn ) + *sn++='\0'; + return helpJavaScriptForTopic( sn ); +} + +void submit(int verify, char **vars) +{ + char line[BIG_LINE]; + char outline[BIG_LINE]; + + if(verify) { + util_snprintf(line, BIG_LINE, "<SCRIPT language="MOCHA_NAME">\n" + "function verify(form) {\n" + " if(confirm('Do you really want to %s?'))\n" + " form.submit();\n" + "}\n" + "</SCRIPT>\n", vars[0]); + output(line); + } + + output("<center><table border=2 width=100%%><tr>"); + + if(!verify) { + util_snprintf(outline, BIG_LINE, "%s%s%s%s%s", + "<td width=33%% align=center>", + "<input type=submit value=\"", + XP_GetAdminStr(DBT_ok_), + "\">", + "</td>\n"); + } else { + util_snprintf(outline, BIG_LINE, "%s%s%s%s%s%s", + "<td width=33%% align=center>", + "<input type=button value=\"", + XP_GetAdminStr(DBT_ok_), + "\" ", + "onclick=\"verify(this.form)\">", + "</td>\n"); + } + output(outline); + util_snprintf(outline, BIG_LINE, "%s%s%s%s", + "<td width=34%% align=center>", + "<input type=reset value=\"", + XP_GetAdminStr(DBT_reset_), + "\"></td>\n"); + output(outline); + + util_snprintf(line, BIG_LINE, "<td width=33%% align=center>%s</td>\n", + _get_help_button( vars[0] )); + output(line); + + output("</tr></table></center>\n"); + + output("</form>\n"); + + output("<SCRIPT language="MOCHA_NAME">\n"); + output("</SCRIPT>\n"); +} + +void helpbutton(char *topic) +{ + output("<form><p><div align=right><table width=33%% border=2>" + "<tr><td align=center>"); + output(_get_help_button(topic)); + output("</td></tr></table></div></form>\n"); + output("<SCRIPT language="MOCHA_NAME">\n"); + output("</SCRIPT>\n"); +} + +void dialogsubmit(char *topic) +{ + char line[BIG_LINE]; + char outline[BIG_LINE]; + + output("<center><table border=2 width=100%%><tr>"); + + util_snprintf(outline, BIG_LINE, "%s%s%s%s%s", + "<td width=33%% align=center>", + "<input type=submit value=\"", + XP_GetAdminStr(DBT_done_), + "\">", + "</td>\n"); + output(outline); + util_snprintf(outline, BIG_LINE, "%s%s%s%s%s", + "<td width=34%% align=center>", + "<input type=button value=\"", + XP_GetAdminStr(DBT_cancel_), + "\" " + "onClick=\"top.close()\"></td>\n"); + output(outline); + + util_snprintf(line, BIG_LINE, "<td width=33%% align=center>%s</td>\n", + _get_help_button(topic)); + output(line); + + output("</tr></table></center>\n"); + + output("</form>\n"); + + output("<SCRIPT language="MOCHA_NAME">\n"); + output("</SCRIPT>\n"); +} + +void helpjsfn(void) +{ + char *tmp; + char line[BIG_LINE]; + char *server=get_srvname(0); + char *type; + int typeLen; + + /* Get the server type, without the instance name into type */ + tmp = strchr( server, '-' ); + typeLen = tmp - server; + + type = (char *)MALLOC( typeLen + 1 ); + type[typeLen] = '\0'; + while ( typeLen-- ) { + type[typeLen] = server[typeLen]; + } + + output("function displayHelpTopic(topic)\n"); + output("{\n"); + util_snprintf(line, BIG_LINE, + " if (top.helpwin) {\n" + " top.helpwin.focus();\n" + " top.helpwin.infotopic.location='%s/%s/admin/tutor?!' + topic;\n" + " } else {\n" + " window.open('%s/%s/admin/tutor?' + topic, '" + INFO_IDX_NAME"_%s', " + HELP_WIN_OPTIONS");\n" + " }\n" + "}\n", + getenv("SERVER_URL"), server, + getenv("SERVER_URL"), server, + type ); + output(line); +} + +void link_referer(char **input, char **vars) +{ + char line[BIG_LINE]; + + sprintf( line, "<SCRIPT language="MOCHA_NAME">\n" + "document.writeln( '%s'.link( '%s' ) );\n" + "</SCRIPT>\n", ( vars[0] ? vars[0] : getenv( "SCRIPT_NAME" ) ), + cookieValue( "adminReferer", NULL ) ); + output( line ); +} + +int get_directive(char *string) +{ + int index = -1; + register int x; + + for(x=0; x < MAXTEMPLATE; x++) { + if(!strncmp(string, templates[x].name, + strlen(templates[x].name))) { + index = x; + break; + } + } + return index; +} + +NSAPI_PUBLIC int directive_is(char *target, char *directive) +{ + char *position = (target + strlen(DIRECTIVE_START)); + return(!(strncmp(directive, position, strlen(directive)))); +} + +char **get_vars(char *string) +{ + char **vars; + register int x; + int isvar; + char scratch[BIG_LINE]; + char lastchar; + +/* Initialize the vars array. + */ + vars = (char **) MALLOC((MAXVARS)*(sizeof(char *))); + for(x=0; x< MAXVARS; x++) + vars[x] = NULL; + + isvar = -1; + x = 0; + scratch[0] = '\0'; + lastchar = ' '; + + while(*string != '\0') { + if((*string == '\"') && (lastchar != '\\')) + if(isvar != -1) { + vars[x++] = (char *)STRDUP(scratch); + isvar = -1; + if(x == MAXVARS) + break; + } else + isvar = 0; + else + if(isvar != -1) { + scratch[isvar++] = *string; + scratch[isvar] = '\0'; + } + else + if(*string == DIRECTIVE_END) + break; + lastchar = *string; + string++; + } + return vars; +} + +static void output(char *line) +{ + if(status) + fputs(line, stdout); +} diff --git a/lib/libadmin/util.c b/lib/libadmin/util.c new file mode 100644 index 00000000..b560055d --- /dev/null +++ b/lib/libadmin/util.c @@ -0,0 +1,1340 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* + * util.c: Miscellaneous stuffs + * + * All blame to Mike McCool + */ + +#include "libadmin/libadmin.h" +#include "base/util.h" +#include "private/pprio.h" + +#ifdef XP_UNIX +#include <dirent.h> +#include <sys/types.h> +#include <fcntl.h> +#else +#include <base/file.h> +#include <sys/stat.h> +#endif /* WIN32? */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <ctype.h> /* isdigit */ + +#define NUM_ENTRIES 64 + +#ifdef MCC_PROXY +char * +XP_GetString() +{ + return "ZAP"; +} +#endif + +#ifdef XP_WIN32 +char *GetQueryNT(void) +{ + char *qs = getenv("QUERY_STRING"); + if(qs && (*qs == '\0')) + qs = NULL; + return qs; +} +#endif /* XP_WIN32 */ + +void escape_for_shell(char *cmd) { + register int x,y,l; + + l=strlen(cmd); + for(x=0;cmd[x];x++) { + if(strchr(" &;`'\"|*!?~<>^()[]{}$\\\x0A",cmd[x])){ + for(y=l+1;y>x;y--) + cmd[y] = cmd[y-1]; + l++; /* length has been increased */ + cmd[x] = '\\'; + x++; /* skip the character */ + } + } +} + +int _admin_dumbsort(const void *s1, const void *s2) +{ + return strcmp(*((char **)s1), *((char **)s2)); +} + +#ifdef XP_UNIX /* WIN32 change */ +/* Lists all files in a directory. */ +char **list_directory(char *path, int dashA) +{ + char **ar; + DIR *ds; + struct dirent *d; + int n, p; + + n = NUM_ENTRIES; + p = 0; + + ar = (char **) MALLOC(n * sizeof(char *)); + + if(!(ds = opendir(path))) { + return NULL; + } + + while( (d = readdir(ds)) ) { + if ( ( d->d_name[0] != '.' ) || + ( dashA && d->d_name[1] && + ( d->d_name[1] != '.' || d->d_name[2] ) ) ) { + if(p == (n-1)) { + n += NUM_ENTRIES; + ar = (char **) REALLOC(ar, n*sizeof(char *)); + } + /* 2: Leave space to add a trailing slash later */ + ar[p] = (char *) MALLOC(strlen(d->d_name) + 2); + strcpy(ar[p++], d->d_name); + } + } + closedir(ds); + + qsort((void *)ar, p, sizeof(char *), _admin_dumbsort); + ar[p] = NULL; + + return ar; +} + +#else /* WIN32 change */ +/* Lists all files in a directory. */ +char **list_directory(char *path, int dashA) +{ + char **ar; + SYS_DIR ds; + SYS_DIRENT *d; + int n, p; + + n = NUM_ENTRIES; + p = 0; + + ar = (char **) MALLOC(n * sizeof(char *)); + + if(!(ds = dir_open(path))) { + return NULL; + } + + while( (d = dir_read(ds)) ) { + if ( ( d->d_name[0] != '.' ) || + ( dashA && d->d_name[1] && + ( d->d_name[1] != '.' || d->d_name[2] ) ) ) { + if(p == (n-1)) { + n += NUM_ENTRIES; + ar = (char **) REALLOC(ar, n*sizeof(char *)); + } + /* 2: Leave space to add a trailing slash later */ + ar[p] = (char *) MALLOC(strlen(d->d_name) + 2); + strcpy(ar[p++], d->d_name); + } + } + dir_close(ds); + + qsort((void *)ar, p, sizeof(char *), _admin_dumbsort); + ar[p] = NULL; + + return ar; +} +#endif /* WIN32 */ + +int file_exists(char *fn) +{ + struct stat finfo; + + if(!stat(fn, &finfo)) + return 1; + else + return 0; +} + +int get_file_size(char *fn) +{ + struct stat finfo; + int ans = -1; + + if(!stat(fn, &finfo)) { + ans = finfo.st_size; + } else { + report_error(FILE_ERROR, fn, "Could not get size of file."); + } + return ans; +} + +int ADM_mkdir_p(char *dir, int mode) +{ + char path[PATH_MAX]; + struct stat fi; + char *slash = NULL; + + if (dir) + strcpy (path, dir); + else + return 0; + + if (slash = strchr(path, FILE_PATHSEP)) + slash++; /* go past root */ + else + return 0; + + while (slash && *slash) { + slash = strchr(slash, FILE_PATHSEP); + if (slash) *slash = '\0'; /* check path till here */ + + if (stat(path, &fi) == -1) { +#ifdef XP_UNIX + if (mkdir(path, mode) == -1) +#else /* XP_WIN32 */ + if (!CreateDirectory(path, NULL)) +#endif + return 0; + } + + if (slash) { + *slash = FILE_PATHSEP; /* restore path */ + slash++; /* check remaining path */ + } + } + return 1; +} + +int ADM_copy_directory(char *src_dir, char *dest_dir) +{ + SYS_DIR ds; + SYS_DIRENT *d; + struct stat fi; + char src_file[PATH_MAX], dest_file[PATH_MAX], fullname[PATH_MAX]; + + if (!(ds = dir_open(src_dir))) + report_error(FILE_ERROR, "Can't read directory", src_dir); + + while (d = dir_read(ds)) { + if (d->d_name[0] != '.') { + sprintf(fullname, "%s/%s", src_dir, d->d_name); + if (system_stat(fullname, &fi) == -1) + continue; + + sprintf(src_file, "%s%c%s", src_dir, FILE_PATHSEP, d->d_name); + sprintf(dest_file, "%s%c%s", dest_dir, FILE_PATHSEP, d->d_name); + if (S_ISDIR(fi.st_mode)) { + char *sub_src_dir = STRDUP(src_file); + char *sub_dest_dir = STRDUP(dest_file); + if (!ADM_mkdir_p(sub_dest_dir, 0755)) { + report_error(FILE_ERROR, "Cannot create directory", + sub_dest_dir); + return 0; + } + if (!ADM_copy_directory(sub_src_dir, sub_dest_dir)) + return 0; + FREE(sub_src_dir); + FREE(sub_dest_dir); + } + else + cp_file(src_file, dest_file, 0644); + } + } + dir_close(ds); + return(1); +} + +void ADM_remove_directory(char *path) +{ + struct stat finfo; + char **dirlisting; + register int x=0; + int stat_good = 0; + char *fullpath = NULL; + +#ifdef XP_UNIX + stat_good = (lstat(path, &finfo) == -1 ? 0 : 1); +#else /* XP_WIN32 */ + stat_good = (stat(path, &finfo) == -1 ? 0 : 1); +#endif + + if(!stat_good) return; + + if(S_ISDIR(finfo.st_mode)) { + dirlisting = list_directory(path,1); + if(!dirlisting) return; + + for(x=0; dirlisting[x]; x++) { + fullpath = (char *) MALLOC(strlen(path) + + strlen(dirlisting[x]) + 4); + sprintf(fullpath, "%s%c%s", path, FILE_PATHSEP, dirlisting[x]); +#ifdef XP_UNIX + stat_good = (lstat(fullpath, &finfo) == -1 ? 0 : 1); +#else /* XP_WIN32 */ + stat_good = (stat(fullpath, &finfo) == -1 ? 0 : 1); +#endif + if(!stat_good) continue; + if(S_ISDIR(finfo.st_mode)) { + ADM_remove_directory(fullpath); + } else { + unlink(fullpath); + } + FREE(fullpath); + } +#ifdef XP_UNIX + rmdir(path); +#else /* XP_WIN32 */ + RemoveDirectory(path); +#endif + } else { + delete_file(path); + } + return; +} + +/* return: mtime(f1) < mtime(f2) ? */ +int mtime_is_earlier(char *file1, char *file2) +{ + struct stat fi1, fi2; + + if(stat(file1, &fi1)) { + return -1; + } + if(stat(file2, &fi2)) { + return -1; + } + return( (fi1.st_mtime < fi2.st_mtime) ? 1 : 0); +} + +time_t get_mtime(char *fn) +{ + struct stat fi; + + if(stat(fn, &fi)) + return 0; + return fi.st_mtime; +} + +int all_numbers(char *target) +{ + register int x=0; + + while(target[x]) + if(!isdigit(target[x++])) + return 0; + return 1; +} + + +int all_numbers_float(char *target) +{ + register int x; + int seenpt; + + for(x = 0, seenpt = 0; target[x]; ++x) { + if((target[x] == '.') && (!seenpt)) + seenpt = 1; + else if((!isdigit(target[x])) && seenpt) + return 0; + } + return 1; +} + +/* Get the admin/config directory. */ +char *get_admcf_dir(int whichone) +{ +#ifdef USE_ADMSERV + char *confdir = NULL; + + char *tmp = get_num_mag_var(whichone, "#ServerRoot"); + if(!tmp) { + /* sigh */ + report_error(INCORRECT_USAGE, "No server root variable", + "The magnus.conf variable #ServerRoot was " + "not set. Please set the value of your server " + "root through the administrative forms."); + } + confdir = (char *) MALLOC(strlen(tmp) + strlen("config") + 4); + sprintf(confdir, "%s%cconfig%c", tmp, FILE_PATHSEP, FILE_PATHSEP); + + return confdir; +#else + char *confdir; + char line[BIG_LINE]; + sprintf(line, "%s%cadmin%cconfig%c", get_mag_var("#ServerRoot"), + FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP); + confdir = STRDUP(line); +#endif + return STRDUP(confdir); +} + +/* Get the current HTTP server URL. */ +char *get_serv_url(void) +{ +#ifdef USE_ADMSERV + char *name = get_mag_var("ServerName"); + char *port = get_mag_var("Port"); + char *protocol = NULL; + char line[BIG_LINE]; + +#ifndef NS_UNSECURE + char *security = get_mag_var("Security"); + + if(!security || strcasecmp(security, "on")) { + protocol = STRDUP("http"); + if(!strcmp(port, "80")) + port = STRDUP(""); + else { + sprintf(line, ":%s", port); + port = STRDUP(line); + } + } else { + protocol = STRDUP("https"); + if(!strcmp(port, "443")) + port = STRDUP(""); + else { + sprintf(line, ":%s", port); + port = STRDUP(line); + } + } +#else + protocol = STRDUP("http"); + if(!strcmp(port, "80")) + port = STRDUP(""); + else { + sprintf(line, ":%s", port); + port = STRDUP(line); + } +#endif + + sprintf(line, "%s://%s%s", protocol, name, port); + return(STRDUP(line)); +#else + return(getenv("SERVER_URL")); +#endif +} + +/* ------------------------------- run_cmd -------------------------------- */ + + +/* Previously in install. This is also pretty UNIX-ish. */ + +/* Nirmal: Added code for Win32 implementation of this function. */ + +#include <signal.h> +#ifdef XP_UNIX +#include <sys/wait.h> +#endif /* XP_UNIX */ + + +int run_cmd(char *cmd, FILE *closeme, struct runcmd_s *rm) +{ +#ifdef WIN32 + HANDLE hproc; + PROCESS_INFORMATION child; + STARTUPINFO siStartInfo ; +#else + struct stat fi; + int exstat; + char *errmsg, tfn[128]; + FILE *f; + int fd; + pid_t pid; +#endif + + +#ifdef WIN32 + /* Nirmal: + For now, i will just spawn + a child in WINNT to execute the command. Communication to + the parent is done through stdout pipe, that was setup by + the parent. + + */ + hproc = OpenProcess(STANDARD_RIGHTS_REQUIRED, FALSE, GetCurrentProcessId()); + if (hproc == NULL) { + fprintf(stdout, "Content-type: text/html\n\n"); + fflush(stdout); + report_error(SYSTEM_ERROR, NULL, "Could not open handle to myself"); + return -1; // stmt. not reached. + } + + ZeroMemory(&child, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.lpReserved = siStartInfo.lpReserved2 = NULL; + siStartInfo.cbReserved2 = 0; + siStartInfo.lpDesktop = NULL; + siStartInfo.dwFlags = STARTF_USESHOWWINDOW; +// Several fields arent used when dwFlags is not set. +// siStartInfo.hStdInput = hChildStdinRd; +// siStartInfo.hStdOutput = siStartInfo.hStdError = hChildStdoutWr; + siStartInfo.wShowWindow = SW_HIDE; + + if ( ! CreateProcess( + NULL, // pointer to name of executable module + cmd, // pointer to command line string + NULL, // pointer to process security attribute + NULL, // pointer to thread security attributes + TRUE, // handle inheritance flag + 0, // creation flags + NULL, // pointer to new environment block + NULL, // pointer to current directory name + &siStartInfo, // pointer to STARTUPINFO + &child // pointer to PROCESS_INFORMATION + )) + { + rm->title = "CreateProcess failed"; + rm->msg = "run_cmd: Can't create new process. "; + rm->arg = ""; + rm->sysmsg = 1; + return -1; + } + else + return 0; +#else + sprintf(cmd, "%s > /tmp/startmsg.%d 2>&1 < /dev/null", cmd, getpid()); /* */ + /* FUCK UNIX SIGNALS. */ + signal(SIGCHLD, SIG_DFL); + switch( (pid = fork()) ) { + case 0: + /* Hmm. Work around an apparent bug in stdio. */ + if(closeme) + close(fileno(closeme)); + execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL); + /* DOH! */ + sprintf(tfn, "/tmp/startmsg.%d", getpid()); + if(!(f = fopen(tfn, "w"))) + exit(1); + fprintf(f, "Exec of %s failed. The error was %s.\n", cmd, + system_errmsg()); + fclose(f); + exit(1); + case -1: + rm->title = "Fork failed"; + rm->msg = "Can't create new process. %s"; + rm->arg = ""; + rm->sysmsg = 1; + return -1; + default: + sprintf(tfn, "/tmp/startmsg.%d", getpid()); + + if(waitpid(pid, &exstat, 0) == -1) { + rm->title = "Can't wait for child"; + rm->msg = "Can't wait for process. %s"; + rm->arg = ""; + rm->sysmsg = 1; + return -1; + } + if(exstat) { + if(!(fd = open(tfn, O_RDONLY))) { + rm->title = "Can't open error file"; + rm->msg = "Can't find error file %s."; + rm->arg = cmd; + rm->sysmsg = 1; + return -1; + } + fstat(fd, &fi); + if((fi.st_size > 0) && (fi.st_size < 8192)) { + errmsg = (char *) MALLOC(fi.st_size + 1); + read(fd, errmsg, fi.st_size); + errmsg[fi.st_size] = '\0'; + close(fd); + unlink(tfn); + rm->title = "Command execution failed"; + rm->msg = "The command did not execute. " + "Here is the output:<p>\n<pre>\n%s\n</pre>\n"; + rm->arg = errmsg; + rm->sysmsg = 0; + return -1; + } + else { + close(fd); + unlink(tfn); + + rm->title = "Command execution failed"; + rm->msg = "The command didn't execute, and it did not produce " + "any output. Run <code>%s</code> from the command " + "line and examine the output.\n"; + rm->arg = cmd; + rm->sysmsg = 0; + return -1; + } + } + unlink(tfn); + return 0; + } +#endif /* WIN32 */ + +} + + + +/* This is basically copy_file from the install section, with the error + * reporting changed to match the admin stuff. Since some stuff depends + * on copy_file being the install version, I'll cheat and call this one + * cp_file. */ +#ifdef XP_UNIX + +#define COPY_BUFFER_SIZE 4096 + +void cp_file(char *sfile, char *dfile, int mode) +{ + int sfd, dfd, len; + struct stat fi; + + char copy_buffer[COPY_BUFFER_SIZE]; + unsigned long read_len; + +/* Make sure we're in the right umask */ + umask(022); + + if( (sfd = open(sfile, O_RDONLY)) == -1) + report_error(FILE_ERROR, sfile, "Can't open file for reading."); + + fstat(sfd, &fi); + if(!(S_ISREG(fi.st_mode))) { + close(sfd); + return; + } + len = fi.st_size; + + if( (dfd = open(dfile, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1) + report_error(FILE_ERROR, dfile, "Can't write to file."); + + while(len) { + read_len = len>COPY_BUFFER_SIZE?COPY_BUFFER_SIZE:len; + + if ( (read_len = read(sfd, copy_buffer, read_len)) == -1) { + report_error(FILE_ERROR, sfile, "Error reading file for copy."); + } + + if ( write(dfd, copy_buffer, read_len) != read_len) { + report_error(FILE_ERROR, dfile, "Error writing file for copy."); + } + + len -= read_len; + } + close(sfd); + close(dfd); +} + +#else /* XP_WIN32 */ +void cp_file(char *sfile, char *dfile, int mode) +{ + HANDLE sfd, dfd, MapHandle; + PCHAR fp; + DWORD BytesWritten = 0; + DWORD len; + + if( (sfd = CreateFile(sfile, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) + == INVALID_HANDLE_VALUE) { + report_error(FILE_ERROR, "Cannot open file for reading", sfile); + } + len = GetFileSize(sfd, NULL); + if( (dfd = CreateFile(dfile, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) { + report_error(FILE_ERROR, "Cannot open destination file for writing", + dfile); + } + if (len == 0) + return; + if( (MapHandle = CreateFileMapping(sfd, NULL, PAGE_READONLY, + 0, 0, NULL)) == NULL) { + report_error(FILE_ERROR, "Cannot create file mapping", sfile); + } + if (!(fp = MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0))) { + report_error(FILE_ERROR, "Cannot map file %s", sfile); + } + while ( len) { + if(!WriteFile(dfd, fp, len, &BytesWritten, NULL)) { + report_error(FILE_ERROR, "Cannot write new file", dfile); + } + len -= BytesWritten; + fp += BytesWritten; + } + + CloseHandle(sfd); + UnmapViewOfFile(fp); + CloseHandle(MapHandle); + FlushFileBuffers(dfd); + CloseHandle(dfd); +} +#endif + +int delete_file(char *path) +{ +#ifdef XP_UNIX + return unlink(path); +#else + return !(DeleteFile(path)); +#endif +} + +void create_dir(char *dir, int mode) +{ + if ((dir == (char *) NULL) || (strlen(dir) == 0)) { + report_error(FILE_ERROR, "No directory is specified", + "Could not create a necessary directory."); + } + + if(!file_exists(dir)) { +#ifdef XP_UNIX + if(mkdir(dir, mode) == -1) { +#else /* XP_WIN32 */ + if(!CreateDirectory(dir, NULL)) { + if (GetLastError() != ERROR_ALREADY_EXISTS) +#endif /* XP_WIN32 */ + report_error(FILE_ERROR, dir, + "Could not create a necessary directory."); + } + } +} + +#ifdef XP_UNIX +SYS_FILE lf; +#elif defined(XP_WIN32) +HANDLE lf; +#endif + +char *get_flock_path(void) +{ + char *result=""; + char *port=getenv("SERVER_PORT"); +#ifdef XP_UNIX + result=(char *) MALLOC(strlen("/tmp/lock.%%s.")+strlen(port)+4); + sprintf(result, "/tmp/lock.%%s.%s", port); +#endif + return result; +} + +/* Open a file with locking, close a file with unlocking. */ +FILE *fopen_l(char *path, char *mode) +{ + FILE *f = fopen(path, mode); + char *lockpath; + char *sn=get_srvname(0); + char *flp=FILE_LOCK_PATH; + + if(f == NULL) return NULL; + lockpath=(char *) MALLOC(strlen(sn)+strlen(flp)+16); + sprintf(lockpath, flp, sn); +#ifdef XP_UNIX + if( (lf=system_fopenRW(lockpath)) == SYS_ERROR_FD) + report_error(FILE_ERROR, lockpath, "Could not open file."); + if(system_flock(lf)==IO_ERROR) + report_error(FILE_ERROR, lockpath, "Could not lock file."); +#elif defined(XP_WIN32) + /* Using mutexes because if the CGI program dies, the mutex will be + * automatically released by the OS for another process to grab. + * Semaphores do not have this property; and if the CGI program crashes, + * the admin server would be effectively crippled. + */ + if ( (lf = CreateMutex(NULL, 0, lockpath)) == NULL) { + report_error(FILE_ERROR, lockpath, "Could not create admin mutex."); + } else { + if ( WaitForSingleObject(lf, 60*1000) == WAIT_FAILED) { + report_error(FILE_ERROR, lockpath, "Unable to obtain mutex after 60 seconds."); + } + } +#endif /* XP_UNIX */ + return f; +} + +void fclose_l(FILE *f) +{ + fclose(f); +#ifdef XP_UNIX + if(system_ulock(lf)==IO_ERROR) + report_error(FILE_ERROR, NULL, "Could not unlock lock file."); + system_fclose(lf); +#elif defined(XP_WIN32) + if (lf) { + ReleaseMutex(lf); + CloseHandle(lf); + } +#endif /* XP_UNIX */ +} + +/* Ripped off from the client. (Sorry, Lou.) */ +/* */ +/* The magic set of 64 chars in the uuencoded data */ +unsigned char uuset[] = { +'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T', +'U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n', +'o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7', +'8','9','+','/' }; + +int do_uuencode(unsigned char *src, unsigned char *dst, int srclen) +{ + int i, r; + unsigned char *p; + +/* To uuencode, we snip 8 bits from 3 bytes and store them as +6 bits in 4 bytes. 6*4 == 8*3 (get it?) and 6 bits per byte +yields nice clean bytes + +It goes like this: + AAAAAAAA BBBBBBBB CCCCCCCC +turns into the standard set of uuencode ascii chars indexed by numbers: + 00AAAAAA 00AABBBB 00BBBBCC 00CCCCCC + +Snip-n-shift, snip-n-shift, etc.... + +*/ + + for (p=dst,i=0; i < srclen; i += 3) { + /* Do 3 bytes of src */ + register char b0, b1, b2; + + b0 = src[0]; + if (i==srclen-1) + b1 = b2 = '\0'; + else if (i==srclen-2) { + b1 = src[1]; + b2 = '\0'; + } + else { + b1 = src[1]; + b2 = src[2]; + } + + *p++ = uuset[b0>>2]; + *p++ = uuset[(((b0 & 0x03) << 4) | ((b1 & 0xf0) >> 4))]; + *p++ = uuset[(((b1 & 0x0f) << 2) | ((b2 & 0xc0) >> 6))]; + *p++ = uuset[b2 & 0x3f]; + src += 3; + } + *p = 0; /* terminate the string */ + r = (unsigned char *)p - (unsigned char *)dst;/* remember how many we did */ + + /* Always do 4-for-3, but if not round threesome, have to go + clean up the last extra bytes */ + + for( ; i != srclen; i--) + *--p = '='; + + return r; +} + +char *alert_word_wrap(char *str, int width, char *linefeed) +{ + char *ans = NULL; + int counter=0; + int lsc=0, lsa=0; + register int strc=0, ansc=0; + register int x=0; + + /* assume worst case */ + ans = (char *) MALLOC((strlen(str)*strlen(linefeed))+32); + + for(strc=0, ansc=0; str[strc]; /*none*/) { + if(str[strc]=='\n') { + counter=0; + lsc=0, lsa=0; + for(x=0; linefeed[x]; x++) { + ans[ansc++]=linefeed[x]; + } + strc++; + } else if(str[strc]=='\r') { + strc++; + } else if(str[strc]=='\\') { + ans[ansc++]='\\'; + ans[ansc++]=strc++; + } else { + if(counter==width) { + if(lsc && lsa) { + strc=lsc; + ansc=lsa; + + counter=0; + lsc=0, lsa=0; + for(x=0; linefeed[x]; x++) { + ans[ansc++]=linefeed[x]; + } + strc++; + } else { + /* else, you're a loser, I'm breaking your big word anyway */ + counter=0; + lsc=0, lsa=0; + for(x=0; linefeed[x]; x++) { + ans[ansc++]=linefeed[x]; + } + strc++; + } + } else { + if(str[strc] == ' ') { + lsc=strc; + lsa=ansc; + } + ans[ansc++]=str[strc++]; + counter++; + } + } + } + ans[ansc]='\0'; + return ans; +} + +void remove_directory(char *path) +{ + struct stat finfo; + char **dirlisting; + register int x=0; + int stat_good = 0; + char *fullpath = NULL; + +#ifdef XP_UNIX + stat_good = (lstat(path, &finfo) == -1 ? 0 : 1); +#else /* WIN32 */ + stat_good = (stat(path, &finfo) == -1 ? 0 : 1); +#endif /* XP_UNIX */ + + if(!stat_good) return; + + if(S_ISDIR(finfo.st_mode)) { + dirlisting = list_directory(path,1); + if(!dirlisting) return; + + for(x=0; dirlisting[x]; x++) { + fullpath = (char *) MALLOC(strlen(path) + + strlen(dirlisting[x]) + 4); + sprintf(fullpath, "%s%c%s", path, FILE_PATHSEP, dirlisting[x]); +#ifdef XP_UNIX + stat_good = (lstat(fullpath, &finfo) == -1 ? 0 : 1); +#else /* WIN32 */ + stat_good = (stat(fullpath, &finfo) == -1 ? 0 : 1); +#endif /* XP_UNIX */ + if(!stat_good) continue; + if(S_ISDIR(finfo.st_mode)) { + remove_directory(fullpath); + } else { + fprintf(stdout, "<i>Removing file</i> " + "<code>%s</code><br>\n", fullpath); + unlink(fullpath); + } + FREE(fullpath); + } + fprintf(stdout, "<i>Removing directory</i> " + "<code>%s</code><br>\n", path); +#ifdef XP_UNIX + rmdir(path); +#else /* XP_WIN32 */ + RemoveDirectory(path); +#endif /* XP_WIN32 */ + } else { + fprintf(stdout, "<i>Removing file</i> <code>%s</code><br>\n", path); + unlink(path); + } + return; +} + +int str_flag_to_int(char *str_flag) +{ + if (!str_flag) + return -1; + if (!strcmp(str_flag, "1")) + return 1; + return 0; +} + +/* + * get_ip_and_mask - function to take something that may be an IP Address + * and netmaks, and validate it. It takes two possible + * + * Parmaters: char *candidate + * + * Returns NULL if it isn't a valid IP address and mask. It returns + * the IP address and mask in the form "iii.iii.iii.iii mmm.mmm.mmm.mmm" + * if it is valid. This is in a string dynamicly allocated in this + * function. + * + * Processing: the candidate is assumed to be in one of + * these two formats: + * + * 1. "iii.iii.iii.iii" (returns: "iii.iii.iii.iii 255.255.255.255") + * 2. "iii.iii.iii.iii mmm.mmm.mmm.mmm" + * 3. "iii.*", "iii.iii.*", or "iii.iii.iii.*" + * + * The rules are: + * I. If it has a space in it, it is assumed to be the delimiter in + * format 2. + * II. If it has a "*" in it, it's assumed to be format 3. + * III. If it's in format 3, the net mask returned is: + * 255.0.0.0, 255.255.0.0, or 255.255.255.0 respectivly, + * and parts of the address right of the * is replaced with 0s. + * IV. We use inet_addr on the pieces to validate them. + * + * + */ + +char *get_ip_and_mask(char *candidate) +{ + char work[BIG_LINE]; + + char *p; + char *result = NULL; + int len; + int dots = 0; + int i; + + if (candidate && strlen(candidate) < (unsigned) BIG_LINE) { + + if ((p = strchr(candidate, ' '))) { + len = p-candidate+1; + memcpy(work, candidate, len); + work[len] = '\0'; + if (inet_addr(work) != -1) { + len = strlen(candidate)-strlen(p)-1; + if (len > 0) { + memcpy(work, p+1, len); + work[len] = '\0'; + if (inet_addr(work) != -1) { + result = strdup(candidate); + } + } + } + } + else if ((p = strchr(candidate, '*')) && + (p-candidate > 1 ) && + (*(p-1) == '.') ) { + memset(work, 0, BIG_LINE); + for (i=0; candidate[i]!='*'; ++i) { + if (candidate[i+1] != '*') + work[i] = candidate[i]; + if (candidate[i] == '.') + ++dots; + } + if (dots == 1 || dots == 2 || dots == 3) { + for (i=0; i<4-dots; ++i) { + strcat(work, ".0"); + } + if (inet_addr(work) != -1) { + strcat(work, " "); + p = &work[strlen(work)]; + for (i=0; i<dots; ++i) { + if (i==0) + strcat(work, "255"); + else + strcat(work, ".255"); + } + for (i=0; i<4-dots; ++i) { + strcat(work, ".0"); + } + if (inet_addr(p) != -1) { + result = strdup(work); + } + } + } + } + else { + if (inet_addr(candidate) != -1) { + strcpy(work, candidate); + strcat(work, " 255.255.255.255"); + result = strdup(work); + } + } + } + else + result = NULL; + + return result; +} + +/* do fgets with a filebuffer *, instead of a File *. Can't use util_getline + because it complains if the line is too long. + It does throw away <CR>s, though. + */ +NSAPI_PUBLIC char *system_gets( char *line, int size, filebuffer *fb ) +{ + int c; + int i = 0; + + while ( --size ) { + switch ( c = filebuf_getc( fb ) ) { + case IO_EOF: + line[i] = '\0'; + return i ? line : NULL; + case LF: + line[i] = c; + line[i+1] = '\0'; + return line; /* got a line, and it fit! */ + case IO_ERROR: + return NULL; + case CR: + ++size; + break; + default: + line[i++] = c; + break; + } + } + /* if we got here, then we overran the buffer size */ + line[i] = '\0'; + return line; +} + +#ifndef WIN32 + +/* make a zero length file, no matter how long it was before */ +NSAPI_PUBLIC int +system_zero( SYS_FILE f ) +{ + ftruncate( PR_FileDesc2NativeHandle( f ), 0 ); + return 0; +} + +#endif + +/*********************************************************************** +** FUNCTION: cookieValue +** DESCRIPTION: +** Get the current value of the cookie variable +** INPUTS: var - the name of the cookie variable +** val - if non-NULL, set the in-memory copy of the var +** OUTPUTS: None +** RETURN: NULL if the var doesn't exist, else the value +** SIDE EFFECTS: +** Eats memory +** RESTRICTIONS: +** Don't screw around with the returned string, if anything else wants +** to use it. +** MEMORY: This is a memory leak, so only use it in CGIs +** ALGORITHM: +** If it's never been called, build a memory structure of the +** cookie variables. +** Look for the passed variable, and return its value, or NULL +***********************************************************************/ + +NSAPI_PUBLIC char * +cookieValue( char *var, char *val ) +{ + static char **vars = NULL; + static char **vals = NULL; + static int numVars = -1; + int i; + + if ( numVars == -1 ) { /* first time, init the structure */ + char *cookie = getenv( "HTTP_COOKIE" ); + + if ( cookie && *cookie ) { + int len = strlen( cookie ); + int foundVal = 0; + + cookie = STRDUP( cookie ); + numVars = 0; + vars = (char **)MALLOC( sizeof( char * ) ); + vals = (char **)MALLOC( sizeof( char * ) ); + vars[0] = cookie; + for ( i = 0 ; i < len ; ++i ) { + if ( ( ! foundVal ) && ( cookie[i] == '=' ) ) { + vals[numVars++] = cookie + i + 1; + cookie[i] = '\0'; + foundVal = 1; + } else if ( ( cookie[i] == ';' ) && ( cookie[i+1] == ' ' ) ) { + cookie[i] = '\0'; + vals = (char **) REALLOC( vals, + sizeof( char * ) * ( numVars + 1 ) ); + vars = (char **) REALLOC( vars, + sizeof( char * ) * ( numVars + 1 ) ); + vars[numVars] = cookie + i + 2; + i += 2; + foundVal = 0; + } + } + } else { /* no cookie, no vars */ + numVars = 0; + } + } + for ( i = 0 ; i < numVars ; ++i ) { + if ( strcmp( vars[i], var ) == 0 ) { + if ( val ) { + vals[i] = STRDUP( val ); + } else { + return vals[i]; + } + } + } + return NULL; +} + +/*********************************************************************** +** FUNCTION: jsEscape +** DESCRIPTION: +** Escape the usual suspects, so the parser javascript parser won't eat them +** INPUTS: src - the string +** OUTPUTS: NONE +** RETURN: A malloced string, containing the escaped src +** SIDE EFFECTS: +** None, except for more memory being eaten +** RESTRICTIONS: +** None +** MEMORY: One Malloc, you should free this if you care +***********************************************************************/ + +NSAPI_PUBLIC char * +jsEscape( char *src ) +{ + int needsEscaping = 0; + int i; + char *dest; + + for ( i = 0 ; src[i] ; ++i ) { + if ( src[i] == '\\' || src[i] == '\'' || src[i] == '"' ) { + ++needsEscaping; + } + } + dest = (char *)MALLOC( i + needsEscaping + 1 ); + for ( i = 0 ; *src ; ++src ) { + if ( ( *src == '\\' ) || ( *src == '\'' ) || ( *src == '"' ) ) { + dest[i++] = '\\'; /* escape */ + } + dest[i++] = *src; + } + dest[i] = '\0'; + return dest; +} + +/*********************************************************************** +** FUNCTION: jsPWDialogSrc +** DESCRIPTION: +** Put the source to the passwordDialog JavaScript function out. +** INPUTS: inScript - if true, don't put <SCRIPT> stuff out +** otherJS - if nonNULL, other javascript to execute +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** clogs up stdout +** RESTRICTIONS: +** Don't use this outside of a CGI, or before the Content-type: +** MEMORY: No memory change +** ALGORITHM: +** @+@What's really going on? +***********************************************************************/ + +NSAPI_PUBLIC void +jsPWDialogSrc( int inScript, char *otherJS ) +{ + static int srcSpewed = 0; + + otherJS = otherJS ? otherJS : ""; + + if ( ! inScript ) { + fprintf( stdout, "<SCRIPT LANGUAGE=\""MOCHA_NAME"\">\n" ); + } + if ( ! srcSpewed ) { + srcSpewed = 1; + fprintf( stdout, "function passwordDialog( prompt, element ) {\n" + " var dlg = window.open( '', 'dialog', 'height=60,width=500' );\n" + " dlg.document.write(\n" + " '<form name=f1 onSubmit=\"opener.document.'\n" + " + element + '.value = goo.value; window.close(); " + "%s; return false;\">',\n" + " prompt, '<input type=password name=goo></form>' );\n" + " dlg.document.f1.goo.focus();\n" + " dlg.document.close();\n" + "}\n", otherJS ); + } + if ( ! inScript ) { + fprintf( stdout, "</SCRIPT>\n" ); + } +} + +static int adm_initialized=0; + +/* Initialize NSPR for all the base functions we use */ +NSAPI_PUBLIC int ADM_Init(void) +{ + if(!adm_initialized) { + NSPR_INIT("AdminPrograms"); + adm_initialized=1; + } + return 0; +} + + +#ifdef XP_UNIX +/* + * This function will return the SuiteSpot user id and group id used to + * recommend that Netscape Servers to run as. Any line starts with '#' + * is treated as comment. It looks for SuiteSpotUser/SuiteSpotGroup + * name/value pair. + * + * It returns 0 when success and allocate storage for user and group. + * returns -1 when only SuiteSpot user id is found. + * returns -2 when only SuiteSpot group id is found. + * returns -3 when NO SuiteSpot user and group is found. + * returns -4 when fails to open <server_root>/install/ssusers.conf + */ +NSAPI_PUBLIC int ADM_GetUXSSid(char *sroot, char **user, char **group) +{ + int foundUser, foundGroup; + char fn[BIG_LINE]; + char line[BIG_LINE]; + FILE *f; + + foundUser = 0; + foundGroup = 0; + *user = (char *) NULL; + *group = (char *) NULL; + + sprintf(fn, "%s/install/ssusers.conf", sroot); + if (f = fopen(fn, "r")) { + while (fgets(line, sizeof(line), f)) { + if (line[0] == '#') { + continue; + } + if (!strncmp(line, "SuiteSpotUser", strlen("SuiteSpotUser"))) { + char *ptr1; + ptr1 = line + strlen("SuiteSpotUser"); + while ((*ptr1 == '\t') || (*ptr1 == ' ')) { + ptr1++; + } + if ((strlen(ptr1) > 0) && (*user == (char *) NULL)) { + *user = (char *) MALLOC(strlen(ptr1)+1); + if (ptr1[strlen(ptr1)-1] == '\n') { + ptr1[strlen(ptr1)-1] = '\0'; + } + strcpy(*user, ptr1); + } + foundUser = 1; + continue; + } + if (!strncmp(line, "SuiteSpotGroup", strlen("SuiteSpotGroup"))) { + char *ptr1; + ptr1 = line + strlen("SuiteSpotGroup"); + while ((*ptr1 == '\t') || (*ptr1 == ' ')) { + ptr1++; + } + if ((strlen(ptr1) > 0) && (*group == (char *) NULL)) { + *group = (char *) MALLOC(strlen(ptr1)+1); + if (ptr1[strlen(ptr1)-1] == '\n') { + ptr1[strlen(ptr1)-1] = '\0'; + } + strcpy(*group, ptr1); + } + foundGroup = 1; + continue; + } + } + fclose(f); + } else { + return(-4); + } + + if (foundUser && foundGroup) { + return(0); + } else if (foundUser) { + return(-1); + } else if (foundGroup) { + return(-2); + } else { + return(-3); + } +} +#endif /* XP_UNIX */ |