274 lines
8.3 KiB
C
274 lines
8.3 KiB
C
/*
|
|
* Copyright (c) 1989, 1990, 1991 by the University of Washington
|
|
* Copyright (c) 1992, 1993 by the University of Southern California
|
|
*
|
|
* For copying and distribution information, please see the files
|
|
* <uw-copyright.h> and <usc-copyr.h>
|
|
*/
|
|
|
|
#include <uw-copyright.h>
|
|
#include <usc-copyr.h>
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <ardp.h>
|
|
#include <pfs.h>
|
|
#include <plog.h>
|
|
#include <psrv.h>
|
|
#include <pparse.h>
|
|
#include <perrno.h>
|
|
#include <pmachine.h>
|
|
|
|
#include "dirsrv.h"
|
|
|
|
static int vl_delete_attributes(), vl_delete_all_attributes(),
|
|
equal_attribute_names_and_nature();
|
|
|
|
int
|
|
edit_link_info(RREQ req, char **commandp, char **next_wordp, INPUT in,
|
|
char client_dir[], int dir_magic_no)
|
|
{
|
|
VLINK clink; /* For stepping through links */
|
|
PATTRIB at; /* Attributes */
|
|
int tmp; /* Temporary returns from qsscanf() */
|
|
char t_mod_request[ARDP_PTXT_LEN_R];
|
|
enum {ADD, REPLACE, DELETE, DELETE_ALL} e_mod_request;
|
|
char t_name[ARDP_PTXT_LEN_R];
|
|
long n_magic_no = 0;
|
|
VDIR_ST dir_st; /* Directory contents used ... */
|
|
VDIR dir = &dir_st; /* by individual lines */
|
|
int retval;
|
|
vdir_init(dir);
|
|
|
|
if(qsscanf(*next_wordp, "%!!s %!!'s",
|
|
t_mod_request, sizeof t_mod_request, t_name, sizeof t_name) < 2)
|
|
return error_reply(req, "Malformed command: %'s", *commandp);
|
|
if(in_select(in, &n_magic_no))
|
|
return error_reply(req, "EDIT-LINK-INFO: %'s", p_err_string);
|
|
|
|
if (strequal(t_mod_request, "ADD"))
|
|
e_mod_request = ADD;
|
|
else if (strequal(t_mod_request, "DELETE"))
|
|
e_mod_request = DELETE;
|
|
else if (strequal(t_mod_request, "REPLACE"))
|
|
e_mod_request = REPLACE;
|
|
else if (strequal(t_mod_request, "DELETE-ALL"))
|
|
e_mod_request = DELETE_ALL;
|
|
else
|
|
return error_reply(req, "Malformed command: %'s", *commandp);
|
|
|
|
if(in_atrs(in, 0, &at))
|
|
return error_reply(req, "EDIT-LINK-INFO: Could not read attributes \
|
|
from request packet: %'s", p_err_string);
|
|
plog(L_DIR_UPDATE,req,"ELI %s %s %s",client_dir,t_name,t_mod_request,0);
|
|
|
|
|
|
/* XXX: The next 2 screens of code would make a nice routine called
|
|
"find_named_link". Modularize! */
|
|
/* Open the directory. */
|
|
retval = dsrdir(client_dir,dir_magic_no,dir,NULL,0);
|
|
if(retval == DSRFINFO_FORWARDED) {
|
|
dforwarded(req, client_dir, dir_magic_no, dir);
|
|
return PSUCCESS;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
clink = dir->links;
|
|
while(clink) {
|
|
if(strcmp(clink->name,t_name) == 0 && clink->linktype != '-')
|
|
break;
|
|
clink = clink->next;
|
|
}
|
|
if(!clink) {
|
|
clink = dir->ulinks;
|
|
while(clink) {
|
|
if(strcmp(clink->name,t_name) == 0)
|
|
break;
|
|
clink = clink->next;
|
|
}
|
|
}
|
|
if(!clink) {
|
|
creplyf(req,"FAILURE NOT-FOUND LINK %'s\n",t_name);
|
|
plog(L_DIR_ERR,req,"Link not found: %s %s",client_dir, t_name,0);
|
|
vdir_freelinks(dir);
|
|
RETURNPFAILURE;
|
|
}
|
|
/* CLINK is now set to the link we want to modify. */
|
|
|
|
|
|
/* If not authorized, say so */
|
|
if(!srv_check_acl(clink->acl,dir->dacl,req,"m",SCA_LINK,NULL,NULL)) {
|
|
creply(req,"FAILURE NOT-AUTHORIZED\n");
|
|
plog(L_AUTH_ERR,req,"Unauthorized EDIT-LINK-INFO: %s %s",client_dir,
|
|
clink->name,0);
|
|
vdir_freelinks(dir);
|
|
RETURNPFAILURE;
|
|
}
|
|
/* Now that we have the link, and permission to modify it, and the
|
|
attributes, let's go do the modification! */
|
|
switch(e_mod_request) {
|
|
|
|
/* The cases in this switch are ALL RESPONSIBLE FOR DOING THEIR OWN
|
|
ERROR REPORTING upon failure. */
|
|
case ADD:
|
|
/* XXX this isn't really an ADD operation, because we overwrite
|
|
attributes that can only have single instances, without
|
|
complaining. However, it will suffice, since it handles all legal
|
|
requests correctly. */
|
|
/* this reports errors in p_err_string */
|
|
retval = vl_add_atrs(at, clink);
|
|
if (retval) {
|
|
creplyf(req, "FAILURE BAD-VALUE %'s\n", p_err_string);
|
|
plog(L_DIR_ERR, req, "Bad Value for MODIFY-LINK ADD: %'s", p_err_string);
|
|
}
|
|
break;
|
|
case DELETE:
|
|
retval = vl_delete_attributes(req, at, clink);
|
|
atlfree(at);
|
|
break;
|
|
case DELETE_ALL:
|
|
retval = vl_delete_all_attributes(req, at, clink, TRUE);
|
|
atlfree(at);
|
|
break;
|
|
case REPLACE:
|
|
retval = vl_delete_all_attributes(req, at, clink, FALSE);
|
|
if (!retval) {
|
|
retval = vl_add_atrs(at, clink);
|
|
if (retval) {
|
|
creplyf(req, "FAILURE BAD-VALUE %'s\n", p_err_string);
|
|
plog(L_DIR_ERR, req, "Bad Value for MODIFY-LINK REPLACE: %'s",
|
|
p_err_string);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
internal_error("reached default case");
|
|
}
|
|
if(!retval) {
|
|
retval = dswdir(client_dir,dir);
|
|
if(!retval)
|
|
reply(req,"SUCCESS\n");
|
|
else
|
|
creplyf(req,"FAILURE SERVER-FAILED EDIT-LINK-INFO Couldn''''t \
|
|
write the changes to %'s\n", client_dir);
|
|
}
|
|
vdir_freelinks(dir);
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
|
|
/* This does NOT free the attributes to be matched in the ATS list.
|
|
It DOES free the attributes that were deleted. */
|
|
|
|
static
|
|
int
|
|
vl_delete_attributes(req, ats, vl)
|
|
RREQ req;
|
|
PATTRIB ats;
|
|
VLINK vl;
|
|
{
|
|
static int vl_delete_attribute();
|
|
|
|
while(ats) {
|
|
if(vl_delete_attribute(ats, vl)) {
|
|
creplyf(req,"FAILURE NOT-FOUND Could not DELETE attribute %'s; \
|
|
this instance not found", ats->aname);
|
|
plog(L_DIR_ERR,req, "Desired Instance of an attribute not found \
|
|
to delete: %s", ats->aname);
|
|
RETURNPFAILURE;
|
|
} else {
|
|
ats = ats->next;
|
|
}
|
|
}
|
|
return PSUCCESS;
|
|
}
|
|
|
|
|
|
static int
|
|
vl_delete_attribute(at, vl)
|
|
PATTRIB at;
|
|
VLINK vl;
|
|
{
|
|
int retval;
|
|
/* Filter is the only one we need to special-case right now. */
|
|
/* All of the others object attributes have exactly one instance, except
|
|
for ID. */
|
|
if (strequal(at->aname, "ID") && at->nature == ATR_NATURE_FIELD) {
|
|
retval = delete_matching_at(at, &(vl->oid), equal_attributes);
|
|
if (retval == PSUCCESS && strequal(at->value.sequence->token, "REMOTE")
|
|
&& length(at->value.sequence) == 2)
|
|
vl->f_magic_no = 0;
|
|
return retval;
|
|
} else if (strequal(at->aname, "FILTER")
|
|
&& at->nature == ATR_NATURE_FIELD) {
|
|
return delete_matching_fl(at->value.filter, &(vl->filters));
|
|
} else {
|
|
return delete_matching_at(at, &(vl->lattrib), equal_attributes);
|
|
}
|
|
}
|
|
|
|
|
|
static
|
|
int
|
|
vl_delete_all_attributes(req, at, vl, complain)
|
|
RREQ req;
|
|
PATTRIB at;
|
|
VLINK vl;
|
|
int complain; /* TRUE if we object to deleting indelible
|
|
or non-present attributes. FALSE if we
|
|
don't mind. XXX -- currently ignored. */
|
|
{
|
|
static int vl_delete_all_attribute();
|
|
PATTRIB ind;
|
|
for (ind = at; ind; ind = ind->next) {
|
|
while(vl_delete_all_attribute(ind, vl) == PSUCCESS)
|
|
;
|
|
}
|
|
return PSUCCESS;
|
|
|
|
}
|
|
|
|
/* If there's more than one instance of the attribute, we delete only one.
|
|
Must be called repeatedly in order to really delete all of them. */
|
|
|
|
static
|
|
int
|
|
vl_delete_all_attribute(at, vl)
|
|
PATTRIB at;
|
|
VLINK vl;
|
|
{
|
|
static int equal_attribute_names_and_nature(PATTRIB, PATTRIB);
|
|
|
|
if (strequal(at->aname, "ID") && at->nature == ATR_NATURE_FIELD) {
|
|
atlfree(vl->oid);
|
|
vl->oid = NULL;
|
|
vl->f_magic_no = 0;
|
|
} else if (strequal(at->aname, "FILTER")
|
|
&& at->nature == ATR_NATURE_FIELD) {
|
|
fllfree(vl->filters);
|
|
vl->filters = NULL;
|
|
} else {
|
|
return delete_matching_at(at, &(vl->lattrib),
|
|
equal_attribute_names_and_nature);
|
|
}
|
|
return(PSUCCESS);
|
|
}
|
|
|
|
|
|
static
|
|
int
|
|
equal_attribute_names_and_nature(at1, at2)
|
|
PATTRIB at1, at2;
|
|
{
|
|
return at1->nature == at2->nature && strequal(at1->aname,at2->aname);
|
|
}
|