archie/prospero/server/create_obj.c
2024-05-27 16:13:40 +02:00

219 lines
7.2 KiB
C

/*
* Copyright (c) 1992, 1993 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-license.h>
*/
#include <usc-license.h>
#include <stdio.h>
#include <string.h>
#include <ardp.h>
#include <pfs.h>
#include <plog.h>
#include <psrv.h>
#include <perrno.h>
#include <pmachine.h>
#include "dirsrv.h"
/*
* Modified 6/4/93, swa: It now writes out the child directory first.
* It only writes out the changed parent directory if the child directory
* was successfully written. This means that if we have trouble writing the
* child directory, we don't end up with a parent directory containing
* a link to a nonexistent object.
*/
/*
* Modified 11/2/93, swa: Now allocates VIRTUAL subdirectories out of an
* object pool if the parent is not NONATIVE. This solves the previous buggy
* method of creating VIRTUAL subdirectories of real UNIX directories.
*/
ACL aclcopy(ACL acl);
static VLINK
gensym_child(VDIR dir, char *newdir_parent, char *child_linkname,
char **child_hsonamep);
/* This was create_directory */
int
create_object(RREQ req, char **commandp, char **next_wordp, INPUT in,
char client_dir[], int dir_magic_no)
{
AUTOSTAT_CHARPP(t_optionsp); /* options to command. */
AUTOSTAT_CHARPP(child_linknamep); /* link name in parent. */
AUTOSTAT_CHARPP(child_hsonamep); /* HSONAME for the child. */
VLINK clink; /* For the child directory. */
int tmp;
int lpriv; /* LPRIV option */
int retval;
VDIR_ST dir_st; /* Parent directory contents. */
VDIR dir = &dir_st;
VDIR_ST new_dir_st; /* Child directory contents. */
VDIR new_dir = &new_dir_st;
/* Now set object_pool in dirsrv.c */
/* still have to read the remainder of the attributes */
tmp = qsscanf(*next_wordp,"%'&s %'&s",
t_optionsp, child_linknamep);
/* Log and return a better message */
if(tmp < 2) {
creply(req,"ERROR too few arguments");
plog(L_DIR_PERR,req,"Too few arguments: %s",
*commandp, 0);
RETURNPFAILURE;
}
/* For now, VIRTUAL and DIRECTORY options must be specified */
if(!sindex(*t_optionsp, "VIRTUAL")
|| !sindex(*t_optionsp, "DIRECTORY")) {
creply(req,"ERROR only VIRTUAL directories implemented\n");
plog(L_DIR_PERR,req,"Tried to create non-VIRTUAL or
non-directory object: %'s",
*commandp, 0);
RETURNPFAILURE;
}
if(sindex(*t_optionsp,"LPRIV")) lpriv = 1;
else lpriv = 0;
plog(L_DIR_UPDATE,req,"%s", *commandp, 0);
vdir_init(dir);
retval = dsrdir(client_dir,dir_magic_no,dir,NULL,0);
if(retval == DSRFINFO_FORWARDED)
return dforwarded(req, client_dir, dir_magic_no, dir);
/* If not a directory, say so */
if(retval == DSRDIR_NOT_A_DIRECTORY) {
creply(req,"FAILURE NOT-A-DIRECTORY\n");
plog(L_DIR_ERR,req,"Invalid directory name: %'s", client_dir,0);
RETURNPFAILURE;
}
/* If not authorized, say so */
if(!srv_check_acl(dir->dacl,NULL,req,"I",SCA_DIRECTORY,client_dir,NULL)) {
creply(req,"FAILURE NOT-AUTHORIZED\n");
plog(L_AUTH_ERR,req,"Unauthorized CREATE-DIRECTORY: %s %s",client_dir,
*child_linknamep);
/* Free the directory links */
vdir_freelinks(dir);
RETURNPFAILURE;
}
clink = gensym_child(dir, client_dir, *child_linknamep, child_hsonamep);
if (!clink) {
creply(req, "FAILURE SERVER-FAILED Could not generate a unique \
hsoname for the new directory.\n");
vdir_freelinks(dir);
RETURNPFAILURE;
}
retval = vl_insert(clink,dir,VLI_NOCONFLICT);
if(retval == VL_INSERT_ALREADY_THERE) {
creplyf(req,"FAILURE ALREADY-EXISTS %'s\n",clink->name);
/* Free the directory links */
vdir_freelinks(dir);
RETURNPFAILURE;
}
else if(retval == VL_INSERT_CONFLICT) {
creplyf(req,"FAILURE NAME-CONFLICT %'s\n",clink->name);
plog(L_DIR_ERR,req,"Conflicting link already exists: %s %s",client_dir,
clink->name,0);
/* Free the directory links */
vdir_freelinks(dir);
RETURNPFAILURE;
}
/* Don't write out the parent yet! */
/* Initialize the new directory. The child will get a copy of the parent's
ACL. */
vdir_init(new_dir);
new_dir->inc_native = VDIN_NONATIVE;
/* Add creator to the ACL */
if(!lpriv || (!srv_check_acl(dir->dacl,NULL,req,"BIlr",
SCA_DIRECTORY,client_dir,NULL))) {
/* need to copy since EACL_ADD may change it */
new_dir->dacl = aclcopy(dir->dacl);
if(lpriv) srv_add_client_to_acl("AIlr",req,&(new_dir->dacl),
EACL_DIRECTORY);
else srv_add_client_to_acl("ALRWDE",req,&(new_dir->dacl),
EACL_DIRECTORY);
}
else {
new_dir->dacl = dir->dacl;
}
if(!retval) retval = dswdir(*child_hsonamep,new_dir);
/* Ok, now we can write out the parent. */
if(!retval) retval = dswdir(client_dir,dir);
/* Free the entries */
if (dir->dacl == new_dir->dacl) new_dir->dacl = NULL; /* don't free twice*/
vdir_freelinks(dir);
vdir_freelinks(new_dir);
/* if successful say so (need to clean this up) */
if(!retval) reply(req,"SUCCESS\n");
else creply(req,"FAILURE\n");
return retval;
}
/* Gensym a vlink for the child directory. */
static VLINK
gensym_child(VDIR dir, char *newdir_parent, char *child_linkname,
char **child_hsonamep)
{
VDIR_ST tmp_dir_st; /* scratch directory */
VDIR tmp_dir = &tmp_dir_st; /* scratch directory */
int retval; /* value returned by dsrdir() */
/* Allocate a link for the child directory. */
VLINK clink = vlalloc();
clink->name = stcopyr(child_linkname,clink->name);
clink->target = stcopyr("DIRECTORY",clink->target);
clink->host = stcopyr(hostwport,clink->host);
/* come up with an unused hsoname for the new directory. */
*child_hsonamep = qsprintf_stcopyr(*child_hsonamep, "%s/%s",
dir->inc_native == VDIN_NONATIVE ? newdir_parent : object_pool,
child_linkname);
/* Try first a name unadorned with a :# */
vdir_init(tmp_dir);
retval = dsrdir(*child_hsonamep, 0L, tmp_dir, (VLINK) NULL, 0);
if (retval == PSUCCESS) {
char *template = NULL;
int i;
template = qsprintf_stcopyr(template, "%s:%%d", *child_hsonamep);
i = 1;
for (;;) {
*child_hsonamep = qsprintf_stcopyr(*child_hsonamep, template, i);
vdir_freelinks(tmp_dir);
retval = dsrdir(*child_hsonamep, 0L, tmp_dir, (VLINK) NULL, 0);
if (retval != PSUCCESS)
/* Either *child_hsonamep now has an unused name or reading that
directory failed for some reason we can't do much about */
break;
++i;
}
}
vdir_freelinks(tmp_dir);
if (retval != DSRDIR_NOT_A_DIRECTORY) {
/* dsrdir() failed for some reason other than because *child_hsonamep was
unused. We can't do much about it here if it wasn't caught when
reading the parent. */
vlfree(clink);
return NULL;
}
clink->hsoname = stcopyr(*child_hsonamep, clink->hsoname);
return clink;
}