summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2001-01-22 18:10:20 +0000
committerJeremy Allison <jra@samba.org>2001-01-22 18:10:20 +0000
commitea05e9be70a54259bc0321d57e4aa7b3c6423d52 (patch)
treebb20c20299e69f37ae73b094b0844edecf26c154
parentc7a6dc40fac0c6b5e979c470996d4a2bdeb587c5 (diff)
downloadsamba-ea05e9be70a54259bc0321d57e4aa7b3c6423d52.tar.gz
samba-ea05e9be70a54259bc0321d57e4aa7b3c6423d52.tar.xz
samba-ea05e9be70a54259bc0321d57e4aa7b3c6423d52.zip
Fixes to sync up with appliance-head. Fix from Kenichi Okuyama for a typo
in loadparm.c Removed extra \n in configure. Jeremy.
-rwxr-xr-xsource/configure25
-rw-r--r--source/configure.in2
-rw-r--r--source/lib/util_seaccess.c147
-rw-r--r--source/param/loadparm.c2
-rw-r--r--source/printing/nt_printing.c32
-rw-r--r--source/printing/printing.c79
-rw-r--r--source/rpc_server/srv_spoolss_nt.c4
-rw-r--r--source/smbd/lanman.c7
8 files changed, 216 insertions, 82 deletions
diff --git a/source/configure b/source/configure
index ebe9bb19c48..b06bc7d668c 100755
--- a/source/configure
+++ b/source/configure
@@ -11422,9 +11422,10 @@ fi
# If we don't have all of these then disable large
# file support.
#
-echo "checking if large file support can be enabled"
+echo $ac_n "checking checking if large file support can be enabled""... $ac_c" 1>&6
+echo "configure:11427: checking checking if large file support can be enabled" >&5
cat > conftest.$ac_ext <<EOF
-#line 11428 "configure"
+#line 11429 "configure"
#include "confdefs.h"
#if defined(HAVE_LONGLONG) && (defined(HAVE_OFF64_T) || (defined(SIZEOF_OFF_T) && (SIZEOF_OFF_T == 8)))
@@ -11437,7 +11438,7 @@ int main() {
int i
; return 0; }
EOF
-if { (eval echo configure:11441: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:11442: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
samba_cv_HAVE_EXPLICIT_LARGEFILE_SUPPORT=yes
else
@@ -11504,7 +11505,7 @@ fi
# check for POSIX ACL support
echo $ac_n "checking whether to support POSIX ACLs""... $ac_c" 1>&6
-echo "configure:11508: checking whether to support POSIX ACLs" >&5
+echo "configure:11509: checking whether to support POSIX ACLs" >&5
# Check whether --with-posix-acls or --without-posix-acls was given.
if test "${with_posix_acls+set}" = set; then
withval="$with_posix_acls"
@@ -11512,7 +11513,7 @@ if test "${with_posix_acls+set}" = set; then
yes)
echo $ac_n "checking for acl_get_file in -lacl""... $ac_c" 1>&6
-echo "configure:11516: checking for acl_get_file in -lacl" >&5
+echo "configure:11517: checking for acl_get_file in -lacl" >&5
ac_lib_var=`echo acl'_'acl_get_file | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -11520,7 +11521,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lacl $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 11524 "configure"
+#line 11525 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
@@ -11531,7 +11532,7 @@ int main() {
acl_get_file()
; return 0; }
EOF
-if { (eval echo configure:11535: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:11536: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -11559,13 +11560,13 @@ else
fi
echo $ac_n "checking for POSIX ACL support""... $ac_c" 1>&6
-echo "configure:11563: checking for POSIX ACL support" >&5
+echo "configure:11564: checking for POSIX ACL support" >&5
if eval "test \"`echo '$''{'samba_cv_HAVE_POSIX_ACLS'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 11569 "configure"
+#line 11570 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <sys/acl.h>
@@ -11573,7 +11574,7 @@ int main() {
acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);
; return 0; }
EOF
-if { (eval echo configure:11577: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:11578: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
samba_cv_HAVE_POSIX_ACLS=yes
else
@@ -11612,11 +11613,11 @@ if test "$cross_compiling" = yes; then
:
else
cat > conftest.$ac_ext <<EOF
-#line 11616 "configure"
+#line 11617 "configure"
#include "confdefs.h"
#include "${srcdir-.}/tests/summary.c"
EOF
-if { (eval echo configure:11620: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:11621: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
then
echo "configure OK";
else
diff --git a/source/configure.in b/source/configure.in
index a40c9c7de9f..34c5da78cc0 100644
--- a/source/configure.in
+++ b/source/configure.in
@@ -1905,7 +1905,7 @@ fi
# If we don't have all of these then disable large
# file support.
#
-echo "checking if large file support can be enabled"
+AC_MSG_CHECKING(checking if large file support can be enabled)
AC_TRY_COMPILE([
#if defined(HAVE_LONGLONG) && (defined(HAVE_OFF64_T) || (defined(SIZEOF_OFF_T) && (SIZEOF_OFF_T == 8)))
#include <sys/types.h>
diff --git a/source/lib/util_seaccess.c b/source/lib/util_seaccess.c
index 68f900b34db..6cfcd065aad 100644
--- a/source/lib/util_seaccess.c
+++ b/source/lib/util_seaccess.c
@@ -51,32 +51,6 @@ static uint32 check_ace(SEC_ACE *ace, NT_USER_TOKEN *token, uint32 acc_desired,
{
uint32 mask = ace->info.mask;
-#if 0
-
- /* I think there is some aspect of inheritable ACEs that we don't
- understand. A 'Manage Documents' permission has the following
- ACE entries (after generic mapping has been applied):
-
- S-1-5-21-1067277791-1719175008-3000797951-1033 0 9 0x000f000c
- S-1-5-21-1067277791-1719175008-3000797951-1033 0 2 0x00020000
-
- Now a user wanting to print calls se_access_check() with desired
- access PRINTER_ACCESS_USE (0x00000008). This is only allowed if
- the inherit only ACE, flags & SEC_ACE_FLAG_INHERIT_ONLY (0x8) is
- checked. A similar argument is used to explain how a user with
- 'Full Control' permission can print.
-
- Having both the flags SEC_ACE_FLAG_INHERIT_ONLY and
- SEC_ACE_FLAG_OBJECT_INHERIT set in an ACE doesn't seem to make
- sense. According to the MSDN, an inherit only ACE "indicates an
- [...] ACE which does not control access to the object to which
- it is attached" and an object inherit ACE for "non-container
- child objects [they] inherit the ACE as an effective ACE".
- These two flags don't seem to make sense when combined. Does
- the object inherit override the inherit only flag? We are also
- talking about access to a printer object, not a printer job so
- inheritance shouldn't even be involved. -tpot */
-
/*
* Inherit only is ignored.
*/
@@ -85,8 +59,6 @@ static uint32 check_ace(SEC_ACE *ace, NT_USER_TOKEN *token, uint32 acc_desired,
return acc_desired;
}
-#endif
-
/*
* If this ACE has no SID in common with the token,
* ignore it as it cannot be used to make an access
@@ -328,3 +300,122 @@ BOOL se_access_check(SEC_DESC *sd, struct current_user *user,
DEBUG(5,("se_access_check: access (%x) denied.\n", (unsigned int)acc_desired ));
return False;
}
+
+/* Create a child security descriptor using another security descriptor as
+ the parent container. This child object can either be a container or
+ non-container object. */
+
+SEC_DESC_BUF *se_create_child_secdesc(SEC_DESC *parent_ctr,
+ BOOL child_container)
+{
+ SEC_DESC_BUF *sdb;
+ SEC_DESC *sd;
+ SEC_ACL *new_dacl, *acl;
+ SEC_ACE *new_ace_list = NULL;
+ int new_ace_list_ndx = 0, i;
+ size_t size;
+
+ /* Currently we only process the dacl when creating the child. The
+ sacl should also be processed but this is left out as sacls are
+ not implemented in Samba at the moment.*/
+
+ acl = parent_ctr->dacl;
+
+ if (!(new_ace_list = malloc(sizeof(SEC_ACE) * acl->num_aces)))
+ return NULL;
+
+ for (i = 0; acl && i < acl->num_aces; i++) {
+ SEC_ACE *ace = &acl->ace[i];
+ SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
+ uint8 new_flags = 0;
+ BOOL inherit = False;
+ fstring sid_str;
+
+ /* The OBJECT_INHERIT_ACE flag causes the ACE to be
+ inherited by non-container children objects. Container
+ children objects will inherit it as an INHERIT_ONLY
+ ACE. */
+
+ if (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
+
+ if (!child_container) {
+ new_flags |= SEC_ACE_FLAG_OBJECT_INHERIT;
+ } else {
+ new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+ }
+
+ inherit = True;
+ }
+
+ /* The CONAINER_INHERIT_ACE flag means all child container
+ objects will inherit and use the ACE. */
+
+ if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
+ if (!child_container) {
+ inherit = False;
+ } else {
+ new_flags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
+ }
+ }
+
+ /* The INHERIT_ONLY_ACE is not used by the se_access_check()
+ function for the parent container, but is inherited by
+ all child objects as a normal ACE. */
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ /* Move along, nothing to see here */
+ }
+
+ /* The SEC_ACE_FLAG_NO_PROPAGATE_INHERIT flag means the ACE
+ is inherited by child objects but not grandchildren
+ objects. We clear the object inherit and container
+ inherit flags in the inherited ACE. */
+
+ if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
+ new_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT);
+ }
+
+ /* Add ACE to ACE list */
+
+ if (!inherit)
+ continue;
+
+ init_sec_access(&new_ace->info, ace->info.mask);
+ init_sec_ace(new_ace, &ace->sid, ace->type,
+ new_ace->info, new_flags);
+
+ sid_to_string(sid_str, &ace->sid);
+
+ DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
+ " inherited as %s:%d/0x%02x/0x%08x\n", sid_str,
+ ace->type, ace->flags, ace->info.mask,
+ sid_str, new_ace->type, new_ace->flags,
+ new_ace->info.mask));
+
+ new_ace_list_ndx++;
+ }
+
+ /* Create child security descriptor to return */
+
+ new_dacl = make_sec_acl(ACL_REVISION, new_ace_list_ndx, new_ace_list);
+ safe_free(new_ace_list);
+
+ /* Use the existing user and group sids. I don't think this is
+ correct. Perhaps the user and group should be passed in as
+ parameters by the caller? */
+
+ sd = make_sec_desc(SEC_DESC_REVISION,
+ parent_ctr->owner_sid,
+ parent_ctr->grp_sid,
+ parent_ctr->sacl,
+ new_dacl, &size);
+
+ free_sec_acl(&new_dacl);
+
+ sdb = make_sec_desc_buf(size, sd);
+
+ free_sec_desc(&sd);
+
+ return sdb;
+}
diff --git a/source/param/loadparm.c b/source/param/loadparm.c
index b4f33bd5a7f..a418b0ba765 100644
--- a/source/param/loadparm.c
+++ b/source/param/loadparm.c
@@ -1514,7 +1514,7 @@ FN_GLOBAL_BOOL(lp_kernel_oplocks, &Globals.bKernelOplocks)
FN_GLOBAL_INTEGER(lp_os_level, &Globals.os_level)
FN_GLOBAL_INTEGER(lp_max_ttl, &Globals.max_ttl)
FN_GLOBAL_INTEGER(lp_max_wins_ttl, &Globals.max_wins_ttl)
-FN_GLOBAL_INTEGER(lp_min_wins_ttl, &Globals.max_wins_ttl)
+FN_GLOBAL_INTEGER(lp_min_wins_ttl, &Globals.min_wins_ttl)
FN_GLOBAL_INTEGER(lp_max_log_size, &Globals.max_log_size)
FN_GLOBAL_INTEGER(lp_max_open_files, &Globals.max_open_files)
FN_GLOBAL_INTEGER(lp_maxxmit, &Globals.max_xmit)
diff --git a/source/printing/nt_printing.c b/source/printing/nt_printing.c
index 7b84f951614..9eb7dc12ed3 100644
--- a/source/printing/nt_printing.c
+++ b/source/printing/nt_printing.c
@@ -3003,9 +3003,9 @@ void map_printer_permissions(SEC_DESC *sd)
}
/****************************************************************************
- Check a user has permissions to perform the given operation. We use some
- constants defined in include/rpc_spoolss.h that look relevant to check
- the various actions we perform when checking printer access.
+ Check a user has permissions to perform the given operation. We use the
+ permission constants defined in include/rpc_spoolss.h to check the various
+ actions we perform when checking printer access.
PRINTER_ACCESS_ADMINISTER:
print_queue_pause, print_queue_resume, update_printer_sec,
@@ -3015,7 +3015,7 @@ void map_printer_permissions(SEC_DESC *sd)
PRINTER_ACCESS_USE:
print_job_start
- PRINTER_ACCESS_ADMINISTER (should really be JOB_ACCESS_ADMINISTER):
+ JOB_ACCESS_ADMINISTER:
print_job_delete, print_job_pause, print_job_resume,
print_queue_purge
@@ -3051,14 +3051,34 @@ BOOL print_access_check(struct current_user *user, int snum, int access_type)
/* Get printer security descriptor */
nt_printing_getsec(pname, &secdesc);
+
+ if (access_type == JOB_ACCESS_ADMINISTER) {
+ SEC_DESC_BUF *parent_secdesc = secdesc;
+
+ /* Create a child security descriptor to check permissions
+ against. This is because print jobs are child objects
+ objects of a printer. */
+
+ secdesc = se_create_child_secdesc(parent_secdesc->sec, False);
+
+ free_sec_desc_buf(&parent_secdesc);
+
+ /* Now this is the bit that really confuses me. The access
+ type needs to be changed from JOB_ACCESS_ADMINISTER to
+ PRINTER_ACCESS_ADMINISTER for this to work. Something
+ to do with the child (job) object becoming like a
+ printer?? -tpot */
+
+ access_type = PRINTER_ACCESS_ADMINISTER;
+ }
+
+ /* Check access */
map_printer_permissions(secdesc->sec);
result = se_access_check(secdesc->sec, user, access_type,
&access_granted, &status);
- /* Check access */
-
DEBUG(4, ("access check was %s\n", result ? "SUCCESS" : "FAILURE"));
/* Free mallocated memory */
diff --git a/source/printing/printing.c b/source/printing/printing.c
index 3ce58b5b78b..3a676d29b66 100644
--- a/source/printing/printing.c
+++ b/source/printing/printing.c
@@ -534,6 +534,14 @@ static BOOL print_job_delete1(int jobid)
snum = print_job_snum(jobid);
+ /* Hrm - we need to be able to cope with deleting a job before it
+ has reached the spooler. */
+
+ if (pjob->sysjob == -1) {
+ DEBUG(5, ("attempt to delete job %d not seen by lpr\n",
+ jobid));
+ }
+
if (pjob->spooled && pjob->sysjob != -1) {
/* need to delete the spooled entry */
fstring jobstr;
@@ -580,7 +588,7 @@ BOOL print_job_delete(struct current_user *user, int jobid, int *errcode)
owns their job. */
if (!owner &&
- !print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) {
+ !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
DEBUG(3, ("delete denied by security descriptor\n"));
*errcode = ERROR_ACCESS_DENIED;
return False;
@@ -622,7 +630,7 @@ BOOL print_job_pause(struct current_user *user, int jobid, int *errcode)
owner = is_owner(user, jobid);
if (!owner &&
- !print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) {
+ !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
DEBUG(3, ("pause denied by security descriptor\n"));
*errcode = ERROR_ACCESS_DENIED;
return False;
@@ -673,7 +681,7 @@ BOOL print_job_resume(struct current_user *user, int jobid, int *errcode)
owner = is_owner(user, jobid);
if (!is_owner(user, jobid) &&
- !print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) {
+ !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
DEBUG(3, ("resume denied by security descriptor\n"));
*errcode = ERROR_ACCESS_DENIED;
return False;
@@ -906,11 +914,11 @@ int print_job_start(struct current_user *user, int snum, char *jobname)
BOOL print_job_end(int jobid)
{
struct printjob *pjob = print_job_find(jobid);
- int snum;
+ int snum, ret;
SMB_STRUCT_STAT sbuf;
pstring current_directory;
pstring print_directory;
- char *wd, *p, *printer_name;
+ char *wd, *p;
pstring jobname;
if (!pjob)
@@ -921,12 +929,17 @@ BOOL print_job_end(int jobid)
snum = print_job_snum(jobid);
- if (sys_fstat(pjob->fd, &sbuf) == 0)
+ if (sys_fstat(pjob->fd, &sbuf) == 0) {
pjob->size = sbuf.st_size;
-
- close(pjob->fd);
- pjob->fd = -1;
-
+ close(pjob->fd);
+ pjob->fd = -1;
+ } else {
+ /* Couldn't stat the job file, so something has gone wrong. Cleanup */
+ unlink(pjob->filename);
+ tdb_delete(tdb, print_key(jobid));
+ return False;
+ }
+
if (pjob->size == 0) {
/* don't bother spooling empty files */
unlink(pjob->filename);
@@ -953,7 +966,7 @@ BOOL print_job_end(int jobid)
pstring_sub(jobname, "'", "_");
/* send it to the system spooler */
- print_run_command(snum,
+ ret = print_run_command(snum,
lp_printcommand(snum), NULL,
"%s", p,
"%J", jobname,
@@ -962,19 +975,23 @@ BOOL print_job_end(int jobid)
chdir(wd);
- pjob->spooled = True;
- print_job_store(jobid, pjob);
-
- /* force update the database */
- print_cache_flush(snum);
-
- /* Send a printer notify message */
-
- printer_name = PRINTERNAME(snum);
-
- message_send_all(conn_tdb_ctx(),MSG_PRINTER_NOTIFY, printer_name, strlen(printer_name) + 1, False);
-
- return True;
+ if (ret == 0) {
+ /* The print job has been sucessfully handed over to the back-end */
+
+ pjob->spooled = True;
+ print_job_store(jobid, pjob);
+
+ /* make sure the database is up to date */
+ if (print_cache_expired(snum)) print_queue_update(snum);
+
+ return True;
+ } else {
+ /* The print job was not succesfully started. Cleanup */
+ /* Still need to add proper error return propagation! 010122:JRR */
+ unlink(pjob->filename);
+ tdb_delete(tdb, print_key(jobid));
+ return False;
+ }
}
/* utility fn to enumerate the print queue */
@@ -1186,8 +1203,8 @@ BOOL print_queue_resume(struct current_user *user, int snum, int *errcode)
return False;
}
- /* force update the database */
- print_cache_flush(snum);
+ /* make sure the database is up to date */
+ if (print_cache_expired(snum)) print_queue_update(snum);
/* Send a printer notify message */
@@ -1207,16 +1224,20 @@ BOOL print_queue_purge(struct current_user *user, int snum, int *errcode)
print_status_struct status;
char *printer_name;
int njobs, i;
+ BOOL can_job_admin;
+ can_job_admin = print_access_check(user, snum, JOB_ACCESS_ADMINISTER);
njobs = print_queue_status(snum, &queue, &status);
- if (print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) {
- for (i=0;i<njobs;i++) {
+ for (i=0;i<njobs;i++) {
+ BOOL owner = is_owner(user, queue[i].job);
+
+ if (owner || can_job_admin) {
print_job_delete1(queue[i].job);
}
}
- print_cache_flush(snum);
+ print_queue_update(snum);
safe_free(queue);
/* Send a printer notify message */
diff --git a/source/rpc_server/srv_spoolss_nt.c b/source/rpc_server/srv_spoolss_nt.c
index 5b92a51189f..d838d08c3cd 100644
--- a/source/rpc_server/srv_spoolss_nt.c
+++ b/source/rpc_server/srv_spoolss_nt.c
@@ -5736,8 +5736,8 @@ uint32 _spoolss_deleteprinterdata( POLICY_HND *handle, const UNISTR2 *value)
return ERROR_INVALID_HANDLE;
if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
- DEBUG(3, ("_spoolss_deleteprinterdata: security descriptor change denied by existing "
- "security descriptor\n"));
+ DEBUG(3, ("_spoolss_deleteprinterdata: printer properties "
+ "change denied by existing security descriptor\n"));
return ERROR_ACCESS_DENIED;
}
diff --git a/source/smbd/lanman.c b/source/smbd/lanman.c
index 26cb94ee53b..0899a049eb5 100644
--- a/source/smbd/lanman.c
+++ b/source/smbd/lanman.c
@@ -1945,6 +1945,7 @@ static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param
char *QueueName = skip_string(str2,1);
int errcode = NERR_notsupported;
int snum;
+ extern struct current_user current_user;
/* check it's a supported varient */
if (!(strcsequal(str1,"z") && strcsequal(str2,"")))
@@ -1963,13 +1964,13 @@ static BOOL api_WPrintQueueCtrl(connection_struct *conn,uint16 vuid, char *param
switch (function) {
case 74: /* Pause queue */
- if (print_queue_pause(NULL, snum, &errcode)) errcode = NERR_Success;
+ if (print_queue_pause(&current_user, snum, &errcode)) errcode = NERR_Success;
break;
case 75: /* Resume queue */
- if (print_queue_resume(NULL, snum, &errcode)) errcode = NERR_Success;
+ if (print_queue_resume(&current_user, snum, &errcode)) errcode = NERR_Success;
break;
case 103: /* Purge */
- if (print_queue_purge(NULL, snum, &errcode)) errcode = NERR_Success;
+ if (print_queue_purge(&current_user, snum, &errcode)) errcode = NERR_Success;
break;
}