--- /dev/null
+From: Markus Koschany <apo@debian.org>
+Date: Fri, 21 Sep 2018 15:58:32 +0200
+Subject: CVE-2018-16947
+
+Bug-Debian: https://bugs.debian.org/908616
+Origin: https://www.openafs.org/pages/security/openafs-sa-2018-001-stable16.patch
+---
+ Makefile.in | 2 +-
+ doc/man-pages/pod8/backup.pod | 12 +++
+ doc/man-pages/pod8/butc.pod | 31 ++++++-
+ src/audit/audit.c | 191 +++++++++++++++++++++++++++++++++++++++++
+ src/audit/audit.h | 21 +++++
+ src/bucoord/bucoord_internal.h | 2 +
+ src/bucoord/dump.c | 34 +++++++-
+ src/bucoord/main.c | 5 +-
+ src/butc/Makefile.in | 1 +
+ src/butc/butc_prototypes.h | 5 ++
+ src/butc/tcmain.c | 97 +++++++++++++++++----
+ src/butc/tcprocs.c | 148 ++++++++++++++++++++++++++++---
+ src/butc/tcstatus.c | 57 +++++++++++-
+ 13 files changed, 566 insertions(+), 40 deletions(-)
+
+diff --git a/Makefile.in b/Makefile.in
+index a452b66..15ba0da 100644
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -155,7 +155,7 @@ util: procmgmt des lwp_depinstall rx_depinstall
+ libafscp: util afs volser vlserver rx auth fsint
+ +${COMPILE_PART1} libafscp ${COMPILE_PART2}
+
+-audit: util rx rxkad fsint
++audit: util rx rxkad fsint bubasics
+ +${COMPILE_PART1} audit ${COMPILE_PART2} #TODO
+
+ comerr: util
+diff --git a/doc/man-pages/pod8/backup.pod b/doc/man-pages/pod8/backup.pod
+index 3f62b25..a94d343 100644
+--- a/doc/man-pages/pod8/backup.pod
++++ b/doc/man-pages/pod8/backup.pod
+@@ -188,6 +188,18 @@ interactive mode. The local identity and AFS tokens with which the
+ B<backup> command interpreter enters interactive mode apply to all
+ commands issued during the interactive session.
+
++=item B<-nobutcauth>
++
++Prior to the fix for OPENAFS-SA-2018-001, B<butc> did not allow incoming
++connections to be authenticated. As part of that fix, B<backup> was modified
++to authenticate to the B<butc> services when possible, but a B<backup> utility
++with the security fix will not interoperate with a B<butc> that lacks the fix
++unless this option is passed, which forces the use of unauthenticated
++connections to the B<butc>. Use of this option is strongly disrecommended,
++and it is provided only for backwards compatibility in environments where
++B<backup> and B<butc> communicate over a secure network environment that denies
++access to untrusted parties.
++
+ =item B<-portoffset> <I<TC port offset>>
+
+ Specifies the port offset number of the Tape Coordinator that is to
+diff --git a/doc/man-pages/pod8/butc.pod b/doc/man-pages/pod8/butc.pod
+index 84efbf3..363b00a 100644
+--- a/doc/man-pages/pod8/butc.pod
++++ b/doc/man-pages/pod8/butc.pod
+@@ -8,10 +8,14 @@ butc - Initializes the Tape Coordinator process
+ <div class="synopsis">
+
+ B<butc> S<<< [B<-port> <I<port offset>>] >>> S<<< [B<-debuglevel> (0 | 1 | 2)] >>>
+- S<<< [B<-cell> <I<cell name>>] >>> [B<-noautoquery>] [B<-localauth>] [B<-help>]
++ S<<< [B<-cell> <I<cell name>>] >>> [B<-noautoquery>] [B<-localauth>]
++ [B<-auditlog> <I<file | sysvmq>> [B<-audit-interface> <I<interface>>]]
++ [B<-allow_unauthenticated>] [B<-help>]
+
+ B<butc> S<<< [B<-p> <I<port offset>>] >>> S<<< [B<-d> (0 | 1 | 2)] >>>
+- S<<< [B<-c> <I<cell name>>] >>> [B<-n>] [B<-l>] [B<-h>]
++ S<<< [B<-c> <I<cell name>>] >>> [B<-n>] [B<-l>]
++ [B<-auditl> <I<file | sysvmq>> [-B<-audit-i> <I<interface>>]]
++ [B<-al>] [B<-h>]
+
+ =for html
+ </div>
+@@ -179,6 +183,29 @@ Do not combine this argument with the B<-cell> flag, and use it only when
+ logged on to a server machine as the local superuser C<root>; client
+ machines do not have F</usr/afs/etc/KeyFile> file.
+
++=item B<-auditlog> <I<log path>>
++
++Turns on audit logging, and sets the path for the audit log. The audit
++log records information about RPC calls, including the name of the RPC
++call, the host that submitted the call, the authenticated entity (user)
++that issued the call, the parameters for the call, and if the call
++succeeded or failed.
++
++=item B<-audit-interface> <(file | sysvmq)>
++
++Specifies what audit interface to use. Defaults to C<file>. See
++L<fileserver(8)> for an explanation of each interface.
++
++=item B<-allow_unauthenticated>
++
++By default the B<butc> requires clients performing TC_ RPCs to authenticate
++themselves, behavior introduced in the fix for OPENAFS-SA-2018-001.
++This option reverts to the historical behavior of only using the rxnull
++security class for incoming connections. Use of this option is strongly
++disrecommended; it is provided only for backwards compatibility with older
++clients in environments where B<backup> and B<butc> communicate over a secure
++network that denies access to untrusted parties.
++
+ =item B<-help>
+
+ Prints the online help for this command. All other valid options are
+diff --git a/src/audit/audit.c b/src/audit/audit.c
+index dacbef7..22a44ae 100644
+--- a/src/audit/audit.c
++++ b/src/audit/audit.c
+@@ -31,6 +31,7 @@
+ #include <errno.h>
+
+ #include "afs/afsint.h"
++#include "afs/butc.h"
+ #include <rx/rx.h>
+ #include <rx/rxkad.h>
+ #include "audit.h"
+@@ -152,6 +153,95 @@ audmakebuf(char *audEvent, va_list vaList)
+ bufferPtr += sizeof(struct AFSFid);
+ break;
+ }
++ /* butc tape label */
++ case AUD_TLBL:
++ {
++ struct tc_tapeLabel *label;
++
++ label = (struct tc_tapeLabel *)va_arg(vaList,
++ struct tc_tapeLabel *);
++ if (label)
++ memcpy(bufferPtr, label, sizeof(*label));
++ else
++ memset(bufferPtr, 0, sizeof(*label));
++ bufferPtr += sizeof(label);
++ break;
++ }
++ /* butc dump interface */
++ case AUD_TDI:
++ {
++ struct tc_dumpInterface *di;
++
++ di = (struct tc_dumpInterface *)
++ va_arg(vaList, struct tc_dumpInterface *);
++ if (di)
++ memcpy(bufferPtr, di, sizeof(*di));
++ else
++ memset(bufferPtr, 0, sizeof(*di));
++ bufferPtr += sizeof(*di);
++ break;
++ }
++ /*
++ * butc dump array
++ * An array of dump descriptions, but the AIX audit package assumes fixed
++ * length, so we can only do the first one for now.
++ */
++ case AUD_TDA:
++ {
++ struct tc_dumpArray *da;
++
++ da = (struct tc_dumpArray *)
++ va_arg(vaList, struct tc_dumpArray *);
++ if (da && da->tc_dumpArray_len) {
++ memcpy(bufferPtr, &da->tc_dumpArray_len, sizeof(u_int));
++ bufferPtr += sizeof(u_int);
++ memcpy(bufferPtr, da->tc_dumpArray_val,
++ sizeof(da->tc_dumpArray_val[0]));
++ } else {
++ memset(bufferPtr, 0, sizeof(u_int));
++ bufferPtr += sizeof(u_int);
++ memset(bufferPtr, 0, sizeof(da->tc_dumpArray_val[0]));
++ }
++ bufferPtr += sizeof(da->tc_dumpArray_val[0]);
++ break;
++ }
++ /*
++ * butc restore array
++ * An array of restore descriptions, but the AIX audit package assumes
++ * fixed length, so we can only do the first one for now.
++ */
++ case AUD_TRA:
++ {
++ struct tc_restoreArray *ra;
++
++ ra = (struct tc_restoreArray *)
++ va_arg(vaList, struct tc_restoreArray *);
++ if (ra && ra->tc_restoreArray_len) {
++ memcpy(bufferPtr, &ra->tc_restoreArray_len, sizeof(u_int));
++ bufferPtr += sizeof(u_int);
++ memcpy(bufferPtr, ra->tc_restoreArray_val,
++ sizeof(ra->tc_restoreArray_val[0]));
++ } else {
++ memset(bufferPtr, 0, sizeof(u_int));
++ bufferPtr += sizeof(u_int);
++ memset(bufferPtr, 0, sizeof(ra->tc_restoreArray_val[0]));
++ }
++ bufferPtr += sizeof(ra->tc_restoreArray_val[0]);
++ break;
++ }
++ /* butc tape controller status */
++ {
++ struct tciStatusS *status;
++
++ status = (struct tciStatusS *)va_arg(vaList,
++ struct tciStatusS *);
++ if (status)
++ memcpy(bufferPtr, status, sizeof(*status));
++ else
++ memset(bufferPtr, 0, sizeof(*status));
++ bufferPtr += sizeof(*status);
++ break;
++ }
+ default:
+ #ifdef AFS_AIX32_ENV
+ code =
+@@ -177,6 +267,11 @@ printbuf(int rec, char *audEvent, char *afsName, afs_int32 hostId,
+ char *vaStr;
+ struct AFSFid *vaFid;
+ struct AFSCBFids *vaFids;
++ struct tc_tapeLabel *vaLabel;
++ struct tc_dumpInterface *vaDI;
++ struct tc_dumpArray *vaDA;
++ struct tc_restoreArray *vaRA;
++ struct tciStatusS *vaTCstatus;
+ int num = LogThreadNum();
+ struct in_addr hostAddr;
+ time_t currenttime;
+@@ -274,6 +369,102 @@ printbuf(int rec, char *audEvent, char *afsName, afs_int32 hostId,
+
+ }
+ break;
++ case AUD_TLBL: /* butc tape label */
++ vaLabel = va_arg(vaList, struct tc_tapeLabel *);
++
++ if (vaLabel) {
++ audit_ops->append_msg("TAPELABEL %d:%.*s:%.*s:%u ",
++ vaLabel->size,
++ TC_MAXTAPELEN, vaLabel->afsname,
++ TC_MAXTAPELEN, vaLabel->pname,
++ vaLabel->tapeId);
++ } else {
++ audit_ops->append_msg("TAPELABEL <null>");
++ }
++ break;
++ case AUD_TDI:
++ vaDI = va_arg(vaList, struct tc_dumpInterface *);
++
++ if (vaDI) {
++ audit_ops->append_msg(
++ "TCDUMPINTERFACE %.*s:%.*s:%.*s:%d:%d:%d:%d:%.*s:%.*s:%d:%d:%d:%d:%d ",
++ TC_MAXDUMPPATH, vaDI->dumpPath, TC_MAXNAMELEN, vaDI->volumeSetName,
++ TC_MAXNAMELEN, vaDI->dumpName, vaDI->parentDumpId, vaDI->dumpLevel,
++ vaDI->doAppend,
++ vaDI->tapeSet.id, TC_MAXHOSTLEN, vaDI->tapeSet.tapeServer,
++ TC_MAXFORMATLEN, vaDI->tapeSet.format, vaDI->tapeSet.maxTapes,
++ vaDI->tapeSet.a, vaDI->tapeSet.b, vaDI->tapeSet.expDate,
++ vaDI->tapeSet.expType);
++ } else {
++ audit_ops->append_msg("TCDUMPINTERFACE <null>");
++ }
++ break;
++ case AUD_TDA:
++ vaDA = va_arg(vaList, struct tc_dumpArray *);
++
++ if (vaDA) {
++ u_int i;
++ struct tc_dumpDesc *desc;
++ struct in_addr hostAddr;
++
++ desc = vaDA->tc_dumpArray_val;
++ if (desc) {
++ audit_ops->append_msg("DUMPS %d ", vaDA->tc_dumpArray_len);
++ for (i = 0; i < vaDA->tc_dumpArray_len; i++, desc++) {
++ hostAddr.s_addr = desc->hostAddr;
++ audit_ops->append_msg("DUMP %d:%d:%.*s:%d:%d:%d:%s ",
++ desc->vid, desc->vtype, TC_MAXNAMELEN, desc->name,
++ desc->partition, desc->date, desc->cloneDate,
++ inet_ntoa(hostAddr));
++ }
++ } else {
++ audit_ops->append_msg("DUMPS 0 DUMP 0:0::0:0:0:0.0.0.0");
++ }
++ }
++ break;
++ case AUD_TRA:
++ vaRA = va_arg(vaList, struct tc_restoreArray *);
++
++ if (vaRA) {
++ u_int i;
++ struct tc_restoreDesc *desc;
++ struct in_addr hostAddr;
++
++ desc = vaRA->tc_restoreArray_val;
++ if (desc) {
++ audit_ops->append_msg("RESTORES %d ",
++ vaRA->tc_restoreArray_len);
++ for(i = 0; i < vaRA->tc_restoreArray_len; i++, desc++) {
++ hostAddr.s_addr = desc->hostAddr;
++ audit_ops->append_msg(
++ "RESTORE %d:%.*s:%d:%d:%d:%d:%d:%d:%d:%s:%.*s:%.*s ",
++ desc->flags, TC_MAXTAPELEN, desc->tapeName,
++ desc->dbDumpId, desc->initialDumpId,
++ desc->position, desc->origVid, desc->vid,
++ desc->partition, desc->dumpLevel,
++ inet_ntoa(hostAddr), TC_MAXNAMELEN,
++ desc->oldName, TC_MAXNAMELEN, desc->newName);
++ }
++ } else {
++ audit_ops->append_msg(
++ "RESTORES 0 RESTORE 0::0:0:0:0:0:0:0:0.0.0.0::: ");
++ }
++ }
++ break;
++ case AUD_TSTT:
++ vaTCstatus = va_arg(vaList, struct tciStatusS *);
++
++ if (vaTCstatus)
++ audit_ops->append_msg("TCSTATUS %.*s:%d:%d:%d:%d:%.*s:%d:%d ",
++ TC_MAXNAMELEN, vaTCstatus->taskName,
++ vaTCstatus->taskId, vaTCstatus->flags,
++ vaTCstatus->dbDumpId, vaTCstatus->nKBytes,
++ TC_MAXNAMELEN, vaTCstatus->volumeName,
++ vaTCstatus->volsFailed,
++ vaTCstatus->lastPolled);
++ else
++ audit_ops->append_msg("TCSTATUS <null>");
++ break;
+ default:
+ audit_ops->append_msg("--badval-- ");
+ break;
+diff --git a/src/audit/audit.h b/src/audit/audit.h
+index 0014f86..93413ca 100644
+--- a/src/audit/audit.h
++++ b/src/audit/audit.h
+@@ -23,6 +23,12 @@
+ #define AUD_RESID 20 /* resid in variable list */
+ #define AUD_RSSIZERANGE 21 /* rssizerange in variable list */
+ #define AUD_LOOKUPINFO 22 /* LookupInfo in variable list */
++/* next 5 lines for butc */
++#define AUD_TLBL 30 /* Tape Controller label */
++#define AUD_TDI 31 /* Tape Controller dump interface */
++#define AUD_TDA 32 /* Tape Controller dump array */
++#define AUD_TRA 33 /* Tape Controller restore array */
++#define AUD_TSTT 34 /* Tape Controller status struct */
+
+ /*
+ * Note: the master definitions of these error codes come from *.et
+@@ -287,6 +293,21 @@
+ #define SREMIORemoteGetHSMdata "AFS_RE_HSMdata"
+ #define SREMIOPrefetch "AFS_RE_Prefetch"
+
++#define TC_StartEvent "AFS_TC_Start"
++#define TC_LabelTapeEvent "AFS_TC_LabelTape"
++#define TC_PerformDumpEvent "AFS_TC_PerformDump"
++#define TC_PerformRestoreEvent "AFS_TC_PerformRestore"
++#define TC_ReadLabelEvent "AFS_TC_ReadLabel"
++#define TC_RestoreDbEvent "AFS_TC_RestoreDb"
++#define TC_SaveDbEvent "AFS_TC_SaveDb"
++#define TC_ScanDumpsEvent "AFS_TC_ScanDumps"
++#define TC_TCInfoEvent "AFS_TC_TCInfo"
++#define TC_DeleteDumpEvent "AFS_TC_DeleteDump"
++#define TC_GetStatusEvent "AFS_TC_GetStatus"
++#define TC_EndStatusEvent "AFS_TC_EndStatus"
++#define TC_RequestAbortEvent "AFS_TC_RequestAbort"
++#define TC_ScanStatusEvent "AFS_TC_ScanStatus"
++
+
+ /* prototypes for audit functions */
+ int osi_audit(char *audEvent, afs_int32 errCode, ...);
+diff --git a/src/bucoord/bucoord_internal.h b/src/bucoord/bucoord_internal.h
+index 83622b4..d372ac2 100644
+--- a/src/bucoord/bucoord_internal.h
++++ b/src/bucoord/bucoord_internal.h
+@@ -119,6 +119,8 @@ struct cmd_parmdesc;
+ extern afs_int32 bc_ParseExpiration(struct cmd_parmdesc *paramPtr,
+ afs_int32 *expType, afs_int32 *expDate);
+ /* main.c */
++extern int localauth, nobutcauth;
++extern char tcell[];
+ extern time_t tokenExpires;
+ extern afs_int32 doDispatch(afs_int32, char *[], afs_int32);
+ extern void bc_HandleMisc(afs_int32 code);
+diff --git a/src/bucoord/dump.c b/src/bucoord/dump.c
+index cf0f474..54f0851 100644
+--- a/src/bucoord/dump.c
++++ b/src/bucoord/dump.c
+@@ -17,6 +17,7 @@
+
+ #include <sys/types.h>
+ #include <afs/cmd.h>
++#include <afs/cellconfig.h>
+ #ifdef HAVE_STDINT_H
+ # include <stdint.h>
+ #endif
+@@ -478,15 +479,40 @@ bc_GetConn(struct bc_config *aconfig, afs_int32 aport,
+ struct rx_connection **tconn)
+ {
+ afs_uint32 host;
++ afs_int32 code;
+ unsigned short port;
+ static struct rx_securityClass *rxsc;
++ static afs_int32 scIndex;
+ struct bc_hostEntry *te;
+
+ *tconn = (struct rx_connection *)0;
+
+ /* use non-secure connections to butc */
+- if (!rxsc)
+- rxsc = rxnull_NewClientSecurityObject();
++ if (!rxsc) {
++ struct afsconf_dir *dir;
++ afsconf_secflags flags = AFSCONF_SECOPTS_FALLBACK_NULL;
++ char *cname;
++
++ if (nobutcauth)
++ flags |= AFSCONF_SECOPTS_NOAUTH;
++ if (localauth) {
++ flags |= AFSCONF_SECOPTS_LOCALAUTH;
++ dir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
++ } else {
++ dir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
++ }
++ if (tcell[0] == '\0')
++ cname = NULL;
++ else
++ cname = tcell;
++ /* No need for cell info since butc is not a registered service */
++ code = afsconf_PickClientSecObj(dir, flags, NULL, cname, &rxsc, &scIndex,
++ NULL);
++ if (dir)
++ afsconf_Close(dir);
++ if (code)
++ return -1;
++ }
+ if (!rxsc || !aconfig)
+ return (-1);
+
+@@ -499,8 +525,8 @@ bc_GetConn(struct bc_config *aconfig, afs_int32 aport,
+
+ port = htons(BC_TAPEPORT + aport);
+
+- /* servers is 1; sec index is 0 */
+- *tconn = rx_NewConnection(host, port, 1, rxsc, 0);
++ /* servers is 1 */
++ *tconn = rx_NewConnection(host, port, 1, rxsc, scIndex);
+ return ((*tconn ? 0 : -1));
+ }
+ }
+diff --git a/src/bucoord/main.c b/src/bucoord/main.c
+index 3f38d07..1625069 100644
+--- a/src/bucoord/main.c
++++ b/src/bucoord/main.c
+@@ -54,7 +54,7 @@
+ #include "bucoord_internal.h"
+ #include "bucoord_prototypes.h"
+
+-int localauth, interact;
++int localauth, interact, nobutcauth;
+ char tcell[64];
+
+ /*
+@@ -305,6 +305,7 @@ MyBeforeProc(struct cmd_syndesc *as, void *arock)
+ /* Handling the command line opcode */
+ if (!bcInit) {
+ localauth = ((as && as->parms[14].items) ? 1 : 0);
++ nobutcauth = ((as && as->parms[16].items) ? 1 : 0);
+ if (as && as->parms[15].items)
+ strcpy(tcell, as->parms[15].items->data);
+ else
+@@ -445,6 +446,8 @@ add_std_args(struct cmd_syndesc *ts)
+ cmd_AddParm(ts, "-localauth", CMD_FLAG, CMD_OPTIONAL,
+ "local authentication");
+ cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
++ cmd_AddParm(ts, "-nobutcauth", CMD_FLAG, CMD_OPTIONAL,
++ "no authentication to butc");
+ }
+
+ int
+diff --git a/src/butc/Makefile.in b/src/butc/Makefile.in
+index 078fd6e..0a97ba5 100644
+--- a/src/butc/Makefile.in
++++ b/src/butc/Makefile.in
+@@ -41,6 +41,7 @@ LIBS=${TOP_LIBDIR}/libbudb.a \
+ ${TOP_LIBDIR}/libdes.a \
+ ${TOP_LIBDIR}/librx.a \
+ ${TOP_LIBDIR}/libsys.a \
++ ${TOP_LIBDIR}/libaudit.a \
+ ${TOP_LIBDIR}/liblwp.a \
+ ${TOP_LIBDIR}/libcmd.a \
+ ${TOP_LIBDIR}/libafscom_err.a \
+diff --git a/src/butc/butc_prototypes.h b/src/butc/butc_prototypes.h
+index 1c62c34..85a3799 100644
+--- a/src/butc/butc_prototypes.h
++++ b/src/butc/butc_prototypes.h
+@@ -32,5 +32,10 @@ extern void *saveDbToTape(void *);
+ extern void *restoreDbFromTape(void *);
+ extern void *KeepAlive(void *);
+
++/* tcmain.c */
++
++extern struct afsconf_dir *butc_confdir;
++extern int allow_unauth;
++
+ #endif
+
+diff --git a/src/butc/tcmain.c b/src/butc/tcmain.c
+index 2c4154d..79e1bbf 100644
+--- a/src/butc/tcmain.c
++++ b/src/butc/tcmain.c
+@@ -42,6 +42,7 @@
+ #include <afs/keys.h>
+ #include <afs/volser.h>
+ #include <ubik.h>
++#include <afs/audit.h>
+ #include <afs/com_err.h>
+ #include <errno.h>
+ #include <afs/cmd.h>
+@@ -106,18 +107,12 @@ afs_int32 BufferSize; /* Size in B stored for data */
+ char *centralLogFile;
+ afs_int32 lastLog; /* Log last pass info */
+ int rxBind = 0;
++struct afsconf_dir *butc_confdir;
++int allow_unauth = 0;
+
+ #define ADDRSPERSITE 16 /* Same global is in rx/rx_user.c */
+ afs_uint32 SHostAddrs[ADDRSPERSITE];
+
+-/* dummy routine for the audit work. It should do nothing since audits */
+-/* occur at the server level and bos is not a server. */
+-int
+-osi_audit(void)
+-{
+- return 0;
+-}
+-
+ static afs_int32
+ SafeATOL(char *anum)
+ {
+@@ -843,8 +838,8 @@ xbsa_shutdown(int x)
+ static int
+ WorkerBee(struct cmd_syndesc *as, void *arock)
+ {
+- afs_int32 code;
+- struct rx_securityClass *(securityObjects[1]);
++ afs_int32 code, numClasses;
++ struct rx_securityClass *(nullObjects[1]), **secObjs, **allObjs;
+ struct rx_service *service;
+ time_t tokenExpires;
+ char cellName[64];
+@@ -859,6 +854,8 @@ WorkerBee(struct cmd_syndesc *as, void *arock)
+ PROCESS dbWatcherPid;
+ #endif
+ afs_uint32 host = htonl(INADDR_ANY);
++ char *auditFileName = NULL;
++ char *auditInterface = NULL;
+
+ debugLevel = 0;
+
+@@ -1004,6 +1001,29 @@ WorkerBee(struct cmd_syndesc *as, void *arock)
+ }
+ }
+
++ /* Open the configuration directory */
++ butc_confdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
++ if (butc_confdir == NULL) {
++ TLog(0, "Failed to open server configuration directory");
++ exit(1);
++ }
++
++ /* Start auditing */
++ osi_audit_init();
++ if (as->parms[9].items) {
++ auditFileName = as->parms[9].items->data;
++ }
++ if (auditFileName != NULL)
++ osi_audit_file(auditFileName);
++ if (as->parms[10].items) {
++ auditInterface = as->parms[10].items->data;
++ if (osi_audit_interface(auditInterface)) {
++ TLog(0, "Invalid audit interface '%s'\n", auditInterface);
++ exit(1);
++ }
++ }
++ osi_audit(TC_StartEvent, 0, AUD_END);
++
+ if (as->parms[1].items) {
+ debugLevel = SafeATOL(as->parms[1].items->data);
+ if (debugLevel == -1) {
+@@ -1044,6 +1064,13 @@ WorkerBee(struct cmd_syndesc *as, void *arock)
+
+ localauth = (as->parms[5].items ? 1 : 0);
+ rxBind = (as->parms[8].items ? 1 : 0);
++ allow_unauth = (as->parms[11].items ? 1 : 0);
++
++ if (!allow_unauth && !localauth) {
++ const char *errstr = "Neither -localauth nor -allow_unauthenticated was provided; refusing to start in unintended insecure configuration\n";
++ TLog(0, "%s", (char *)errstr);
++ exit(1);
++ }
+
+ if (rxBind) {
+ afs_int32 ccode;
+@@ -1089,19 +1116,48 @@ WorkerBee(struct cmd_syndesc *as, void *arock)
+
+ /* initialize database support, volume support, and logs */
+
+- /* Create a single security object, in this case the null security
+- * object, for unauthenticated connections, which will be used to control
+- * security on connections made to this server
++ /*
++ * Create security objects for the Rx server functionality. Historically
++ * this was a single rxnull security object, since the tape controller was
++ * run by an operator that had local access to the tape device and some
++ * administrative privilege in the cell (to be able to perform volume-level
++ * accesses), but on a machine that was not necessarily trusted to hold the
++ * cell-wide key.
++ *
++ * Such a configuration is, of course, insecure because anyone can make
++ * inbound RPCs and manipulate the database, including creating bogus
++ * dumps and restoring them! Additionally, in modern usage, butc is
++ * frequently run with -localauth to authenticate its outbound connections
++ * to the volservers and budb with the cell-wide key, in which case the
++ * cell-wide key is present and could be used to authenticate incoming
++ * connections as well.
++ *
++ * If -localauth is in use, create the full barrage of server security
++ * objects, including rxkad, so that inbound connections can be verified
++ * to only be made by authenticated clients. Otherwise, only the rxnull
++ * class is in use with a single server security object. Note that butc
++ * will refuse to start in this configuration unless the
++ * "-allow_unauthenticated" flag is provided, indicating that the operator
++ * has ensured that incoming connections are appropriately restricted by
++ * firewall configuration or network topology.
+ */
+
+- securityObjects[0] = rxnull_NewServerSecurityObject();
+- if (!securityObjects[0]) {
+- TLog(0, "rxnull_NewServerSecurityObject");
+- exit(1);
++ if (allow_unauth) {
++ nullObjects[RX_SECIDX_NULL] = rxnull_NewServerSecurityObject();
++ if (!nullObjects[RX_SECIDX_NULL]) {
++ TLog(0, "rxnull_NewServerSecurityObject");
++ exit(1);
++ }
++ numClasses = 1;
++ secObjs = nullObjects;
++ } else {
++ /* Must be -localauth, so the cell keys are available. */
++ afsconf_BuildServerSecurityObjects(butc_confdir, 0, &allObjs, &numClasses);
++ secObjs = allObjs;
+ }
+
+ service =
+- rx_NewServiceHost(host, 0, 1, "BUTC", securityObjects, 1, TC_ExecuteRequest);
++ rx_NewServiceHost(host, 0, 1, "BUTC", secObjs, numClasses, TC_ExecuteRequest);
+ if (!service) {
+ TLog(0, "rx_NewService");
+ exit(1);
+@@ -1204,6 +1260,11 @@ main(int argc, char **argv)
+ "Force multiple XBSA server support");
+ cmd_AddParm(ts, "-rxbind", CMD_FLAG, CMD_OPTIONAL,
+ "bind Rx socket");
++ cmd_AddParm(ts, "-auditlog", CMD_SINGLE, CMD_OPTIONAL, "location of audit log");
++ cmd_AddParm(ts, "-audit-interface", CMD_SINGLE, CMD_OPTIONAL,
++ "interface to use for audit logging");
++ cmd_AddParm(ts, "-allow_unauthenticated", CMD_FLAG, CMD_OPTIONAL,
++ "allow unauthenticated inbound RPCs (requires firewalling)");
+
+ /* Initialize dirpaths */
+ if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
+diff --git a/src/butc/tcprocs.c b/src/butc/tcprocs.c
+index 9efcbe8..e22a5ca 100644
+--- a/src/butc/tcprocs.c
++++ b/src/butc/tcprocs.c
+@@ -46,18 +46,41 @@
+ #include "butc_xbsa.h"
+ #include "butc_prototypes.h"
+ #include "butc_internal.h"
++#include "afs/audit.h"
+
+ static int CopyDumpDesc(struct tc_dumpDesc *, tc_dumpArray *);
+ static int CopyRestoreDesc(struct tc_restoreDesc *, tc_restoreArray *);
+ static int CopyTapeSetDesc(struct tc_tapeSet *, struct tc_tapeSet *);
+
++/* Helpers implementing RPC backends */
++static afs_int32 SLabelTape(struct rx_call *acid, struct tc_tapeLabel *label,
++ afs_uint32 *taskId);
++static afs_int32 SPerformDump(struct rx_call *rxCallId,
++ struct tc_dumpInterface *tcdiPtr,
++ tc_dumpArray *tc_dumpArrayPtr, afs_int32 *taskId);
++static afs_int32 SPerformRestore(struct rx_call *acid, char *dumpSetName,
++ tc_restoreArray *arestores, afs_int32 *taskId);
++static afs_int32 SReadLabel(struct rx_call *acid, struct tc_tapeLabel *label,
++ afs_uint32 *taskId);
++static afs_int32 SRestoreDb(struct rx_call *rxCall, afs_uint32 *taskId);
++static afs_int32 SSaveDb(struct rx_call *rxCall, Date archiveTime,
++ afs_uint32 *taskId);
++static afs_int32 SScanDumps(struct rx_call *acid, afs_int32 addDbFlag,
++ afs_uint32 *taskId);
++static afs_int32 STCInfo(struct rx_call *acid, struct tc_tcInfo *tciptr);
++static afs_int32 SDeleteDump(struct rx_call *acid, afs_uint32 dumpID,
++ afs_uint32 *taskId);
++
+ int
+ callPermitted(struct rx_call *call)
+ {
+- /* before this code can be used, the rx connection, on the bucoord side, must */
+- /* be changed so that it will set up for token passing instead of using a */
+- /* simple rx connection that, below, returns a value of 0 from rx_SecurityClassOf */
+- return 1;
++ /*
++ * If in backwards compat mode, allow anyone; otherwise, only
++ * superusers are allowed.
++ */
++ if (allow_unauth)
++ return 1;
++ return afsconf_SuperUser(butc_confdir, call, NULL);
+ }
+
+ /* -----------------------------
+@@ -139,6 +162,17 @@ CopyTapeSetDesc(struct tc_tapeSet *toPtr, struct tc_tapeSet *fromPtr)
+
+ afs_int32
+ STC_LabelTape(struct rx_call *acid, struct tc_tapeLabel *label, afs_uint32 *taskId)
++{
++ afs_int32 code;
++
++ code = SLabelTape(acid, label, taskId);
++ osi_auditU(acid, TC_LabelTapeEvent, code,
++ AUD_TLBL, label, AUD_INT, *taskId, AUD_END);
++ return code;
++}
++
++static afs_int32
++SLabelTape(struct rx_call *acid, struct tc_tapeLabel *label, afs_uint32 *taskId)
+ {
+ #ifdef AFS_PTHREAD_ENV
+ pthread_t pid;
+@@ -214,7 +248,20 @@ STC_LabelTape(struct rx_call *acid, struct tc_tapeLabel *label, afs_uint32 *task
+ */
+
+ afs_int32
+-STC_PerformDump(struct rx_call *rxCallId, struct tc_dumpInterface *tcdiPtr, tc_dumpArray *tc_dumpArrayPtr, afs_int32 *taskId)
++STC_PerformDump(struct rx_call *call, struct tc_dumpInterface *di,
++ tc_dumpArray *da, afs_int32 *taskId)
++{
++ afs_int32 code;
++
++ code = SPerformDump(call, di, da, taskId);
++ osi_auditU(call, TC_PerformDumpEvent, code,
++ AUD_TDI, di, AUD_TDA, da, AUD_INT, *taskId, AUD_END);
++ return code;
++}
++
++static afs_int32
++SPerformDump(struct rx_call *rxCallId, struct tc_dumpInterface *tcdiPtr,
++ tc_dumpArray *tc_dumpArrayPtr, afs_int32 *taskId)
+ {
+ struct dumpNode *newNode = 0;
+ statusP statusPtr = 0;
+@@ -310,7 +357,20 @@ STC_PerformDump(struct rx_call *rxCallId, struct tc_dumpInterface *tcdiPtr, tc_d
+ }
+
+ afs_int32
+-STC_PerformRestore(struct rx_call *acid, char *dumpSetName, tc_restoreArray *arestores, afs_int32 *taskID)
++STC_PerformRestore(struct rx_call *call, char *dumpSetName,
++ tc_restoreArray *ra, afs_int32 *taskId)
++{
++ afs_int32 code;
++
++ code = SPerformRestore(call, dumpSetName, ra, taskId);
++ osi_auditU(call, TC_PerformRestoreEvent, code,
++ AUD_STR, dumpSetName, AUD_TRA, ra, AUD_INT, *taskId, AUD_END);
++ return code;
++}
++
++static afs_int32
++SPerformRestore(struct rx_call *acid, char *dumpSetName,
++ tc_restoreArray *arestores, afs_int32 *taskID)
+ {
+ struct dumpNode *newNode;
+ statusP statusPtr;
+@@ -384,7 +444,18 @@ STC_PerformRestore(struct rx_call *acid, char *dumpSetName, tc_restoreArray *are
+ }
+
+ afs_int32
+-STC_ReadLabel(struct rx_call *acid, struct tc_tapeLabel *label, afs_uint32 *taskId)
++STC_ReadLabel(struct rx_call *call, struct tc_tapeLabel *label, afs_uint32 *taskId)
++{
++ afs_int32 code;
++
++ code = SReadLabel(call, label, taskId);
++ osi_auditU(call, TC_ReadLabelEvent, code,
++ AUD_TLBL, label, AUD_INT, *taskId, AUD_END);
++ return code;
++}
++
++static afs_int32
++SReadLabel(struct rx_call *acid, struct tc_tapeLabel *label, afs_uint32 *taskId)
+ {
+ afs_int32 code;
+
+@@ -405,7 +476,17 @@ STC_ReadLabel(struct rx_call *acid, struct tc_tapeLabel *label, afs_uint32 *task
+ */
+
+ afs_int32
+-STC_RestoreDb(struct rx_call *rxCall, afs_uint32 *taskId)
++STC_RestoreDb(struct rx_call *call, afs_uint32 *taskId)
++{
++ afs_int32 code;
++
++ code = SRestoreDb(call, taskId);
++ osi_auditU(call, TC_RestoreDbEvent, code, AUD_INT, *taskId, AUD_END);
++ return code;
++}
++
++static afs_int32
++SRestoreDb(struct rx_call *rxCall, afs_uint32 *taskId)
+ {
+ #ifdef AFS_PTHREAD_ENV
+ pthread_t pid;
+@@ -471,7 +552,18 @@ STC_RestoreDb(struct rx_call *rxCall, afs_uint32 *taskId)
+ */
+
+ afs_int32
+-STC_SaveDb(struct rx_call *rxCall, Date archiveTime, afs_uint32 *taskId)
++STC_SaveDb(struct rx_call *call, Date archiveTime, afs_uint32 *taskId)
++{
++ afs_int32 code;
++
++ code = SSaveDb(call, archiveTime, taskId);
++ osi_auditU(call, TC_SaveDbEvent, code,
++ AUD_DATE, archiveTime, AUD_INT, *taskId, AUD_END);
++ return code;
++}
++
++static afs_int32
++SSaveDb(struct rx_call *rxCall, Date archiveTime, afs_uint32 *taskId)
+ {
+ #ifdef AFS_PTHREAD_ENV
+ pthread_t pid;
+@@ -550,7 +642,18 @@ STC_SaveDb(struct rx_call *rxCall, Date archiveTime, afs_uint32 *taskId)
+ */
+
+ afs_int32
+-STC_ScanDumps(struct rx_call *acid, afs_int32 addDbFlag, afs_uint32 *taskId)
++STC_ScanDumps(struct rx_call *call, afs_int32 addDbFlag, afs_uint32 *taskId)
++{
++ afs_int32 code;
++
++ code = SScanDumps(call, addDbFlag, taskId);
++ osi_auditU(call, TC_ScanDumpsEvent, code,
++ AUD_INT, addDbFlag, AUD_INT, *taskId, AUD_END);
++ return code;
++}
++
++static afs_int32
++SScanDumps(struct rx_call *acid, afs_int32 addDbFlag, afs_uint32 *taskId)
+ {
+ #ifdef AFS_PTHREAD_ENV
+ pthread_t pid;
+@@ -625,7 +728,17 @@ STC_ScanDumps(struct rx_call *acid, afs_int32 addDbFlag, afs_uint32 *taskId)
+ */
+
+ afs_int32
+-STC_TCInfo(struct rx_call *acid, struct tc_tcInfo *tciptr)
++STC_TCInfo(struct rx_call *call, struct tc_tcInfo *ti)
++{
++ afs_int32 code;
++
++ code = STCInfo(call, ti);
++ osi_auditU(call, TC_TCInfoEvent, code, AUD_INT, ti->tcVersion, AUD_END);
++ return code;
++}
++
++static afs_int32
++STCInfo(struct rx_call *acid, struct tc_tcInfo *tciptr)
+ {
+ if (callPermitted(acid) == 0)
+ return (TC_NOTPERMITTED);
+@@ -637,7 +750,18 @@ STC_TCInfo(struct rx_call *acid, struct tc_tcInfo *tciptr)
+ /* STC_DeleteDump
+ */
+ afs_int32
+-STC_DeleteDump(struct rx_call *acid, afs_uint32 dumpID, afs_uint32 *taskId)
++STC_DeleteDump(struct rx_call *call, afs_uint32 dumpID, afs_uint32 *taskId)
++{
++ afs_int32 code;
++
++ code = SDeleteDump(call, dumpID, taskId);
++ osi_auditU(call, TC_DeleteDumpEvent, code,
++ AUD_DATE, dumpID, AUD_INT, *taskId, AUD_END);
++ return code;
++}
++
++static afs_int32
++SDeleteDump(struct rx_call *acid, afs_uint32 dumpID, afs_uint32 *taskId)
+ {
+ afs_int32 code = TC_BADTASK; /* If not compiled -Dxbsa then fail */
+ #ifdef xbsa
+diff --git a/src/butc/tcstatus.c b/src/butc/tcstatus.c
+index 1bd280f..883f46d 100644
+--- a/src/butc/tcstatus.c
++++ b/src/butc/tcstatus.c
+@@ -34,6 +34,8 @@
+
+ #include "error_macros.h"
+ #include "butc_xbsa.h"
++#include "afs/audit.h"
++
+ /* tape coordinator - task status management */
+ extern afs_int32 xbsaType;
+
+@@ -41,6 +43,13 @@ dlqlinkT statusHead;
+ struct Lock statusQueueLock;
+ struct Lock cmdLineLock;
+
++static afs_int32 SGetStatus(struct rx_call *call, afs_uint32 taskId,
++ struct tciStatusS *statusPtr);
++static afs_int32 SEndStatus(struct rx_call *call, afs_uint32 taskId);
++static afs_int32 SRequestAbort(struct rx_call *call, afs_uint32 taskId);
++static afs_int32 SScanStatus(struct rx_call *call, afs_uint32 *taskId,
++ struct tciStatusS *statusPtr, afs_uint32 *flags);
++
+ /* STC_GetStatus
+ * get the status of a task
+ * entry:
+@@ -51,7 +60,19 @@ struct Lock cmdLineLock;
+
+ afs_int32
+ STC_GetStatus(struct rx_call *call, afs_uint32 taskId,
+- struct tciStatusS *statusPtr)
++ struct tciStatusS *status)
++{
++ afs_int32 code;
++
++ code = SGetStatus(call, taskId, status);
++ osi_auditU(call, TC_GetStatusEvent, code,
++ AUD_INT, taskId, AUD_TSTT, status, AUD_END);
++ return code;
++}
++
++static afs_int32
++SGetStatus(struct rx_call *call, afs_uint32 taskId,
++ struct tciStatusS *statusPtr)
+ {
+ statusP ptr;
+ int retval = 0;
+@@ -82,6 +103,16 @@ STC_GetStatus(struct rx_call *call, afs_uint32 taskId,
+
+ afs_int32
+ STC_EndStatus(struct rx_call *call, afs_uint32 taskId)
++{
++ afs_int32 code;
++
++ code = SEndStatus(call, taskId);
++ osi_auditU(call, TC_EndStatusEvent, code, AUD_INT, taskId, AUD_END);
++ return code;
++}
++
++static afs_int32
++SEndStatus(struct rx_call *call, afs_uint32 taskId)
+ {
+ statusP ptr;
+ int retval = 0;
+@@ -103,6 +134,16 @@ STC_EndStatus(struct rx_call *call, afs_uint32 taskId)
+
+ afs_int32
+ STC_RequestAbort(struct rx_call *call, afs_uint32 taskId)
++{
++ afs_int32 code;
++
++ code = SRequestAbort(call, taskId);
++ osi_auditU(call, TC_RequestAbortEvent, code, AUD_INT, taskId, AUD_END);
++ return code;
++}
++
++static afs_int32
++SRequestAbort(struct rx_call *call, afs_uint32 taskId)
+ {
+ statusP ptr;
+ int retval = 0;
+@@ -138,7 +179,19 @@ STC_RequestAbort(struct rx_call *call, afs_uint32 taskId)
+
+ afs_int32
+ STC_ScanStatus(struct rx_call *call, afs_uint32 *taskId,
+- struct tciStatusS *statusPtr, afs_uint32 *flags)
++ struct tciStatusS *status, afs_uint32 *flags)
++{
++ afs_int32 code;
++
++ code = SScanStatus(call, taskId, status, flags);
++ osi_auditU(call, TC_ScanStatusEvent, code,
++ AUD_INT, *taskId, AUD_TSTT, status, AUD_INT, *flags, AUD_END);
++ return code;
++}
++
++static afs_int32
++SScanStatus(struct rx_call *call, afs_uint32 *taskId,
++ struct tciStatusS *statusPtr, afs_uint32 *flags)
+ {
+ statusP ptr = 0;
+ dlqlinkP dlqPtr;
--- /dev/null
+From: Markus Koschany <apo@debian.org>
+Date: Fri, 21 Sep 2018 15:58:50 +0200
+Subject: CVE-2018-16948
+
+Bug-Debian: https://bugs.debian.org/908616
+Origin: https://www.openafs.org/pages/security/openafs-sa-2018-002-stable16.patch
+---
+ src/afs/afs_callback.c | 2 ++
+ src/budb/procs.c | 1 +
+ src/butc/tcprocs.c | 3 +++
+ src/butc/tcstatus.c | 4 ++--
+ src/kauth/kaprocs.c | 1 +
+ src/ptserver/ptprocs.c | 4 ++--
+ src/ubik/vote.c | 1 +
+ src/volser/volprocs.c | 3 +++
+ 8 files changed, 15 insertions(+), 4 deletions(-)
+
+diff --git a/src/afs/afs_callback.c b/src/afs/afs_callback.c
+index 51b6b61..6a95ed4 100644
+--- a/src/afs/afs_callback.c
++++ b/src/afs/afs_callback.c
+@@ -309,6 +309,7 @@ SRXAFSCB_GetLock(struct rx_call *a_call, afs_int32 a_index,
+ XSTATS_START_CMTIME(AFS_STATS_CM_RPCIDX_GETLOCK);
+
+ AFS_STATCNT(SRXAFSCB_GetLock);
++ memset(a_result, 0, sizeof(*a_result));
+ nentries = sizeof(ltable) / sizeof(struct ltable);
+ if (a_index < 0 || a_index >= nentries+afs_cellindex) {
+ /*
+@@ -1632,6 +1633,7 @@ SRXAFSCB_TellMeAboutYourself(struct rx_call *a_call,
+ ObtainReadLock(&afs_xinterface);
+
+ /* return all network interface addresses */
++ memset(addr, 0, sizeof(*addr));
+ addr->numberOfInterfaces = afs_cb_interface.numberOfInterfaces;
+ addr->uuid = afs_cb_interface.uuid;
+ for (i = 0; i < afs_cb_interface.numberOfInterfaces; i++) {
+diff --git a/src/budb/procs.c b/src/budb/procs.c
+index 51f3102..de55834 100644
+--- a/src/budb/procs.c
++++ b/src/budb/procs.c
+@@ -437,6 +437,7 @@ FillDumpEntry(struct ubik_trans *ut, dbadr da, void *rock)
+ struct budb_dumpEntry *dump = (struct budb_dumpEntry *)rock;
+ struct dump d, ad;
+
++ memset(dump, 0, sizeof(*dump));
+ if (dbread(ut, da, &d, sizeof(d)))
+ return BUDB_IO;
+ dump->id = ntohl(d.id);
+diff --git a/src/butc/tcprocs.c b/src/butc/tcprocs.c
+index e22a5ca..25b6d5b 100644
+--- a/src/butc/tcprocs.c
++++ b/src/butc/tcprocs.c
+@@ -459,6 +459,9 @@ SReadLabel(struct rx_call *acid, struct tc_tapeLabel *label, afs_uint32 *taskId)
+ {
+ afs_int32 code;
+
++ memset(label, 0, sizeof(*label));
++ /* Synchronous, so no "real" ID; don't send stack garbage on the wire */
++ *taskId = 0;
+ #ifdef xbsa
+ if (CONF_XBSA)
+ return (TC_BADTASK); /* ReadLabel does not apply if XBSA */
+diff --git a/src/butc/tcstatus.c b/src/butc/tcstatus.c
+index 883f46d..dcc4d19 100644
+--- a/src/butc/tcstatus.c
++++ b/src/butc/tcstatus.c
+@@ -77,14 +77,13 @@ SGetStatus(struct rx_call *call, afs_uint32 taskId,
+ statusP ptr;
+ int retval = 0;
+
++ memset(statusPtr, 0, sizeof(*statusPtr));
+ if (callPermitted(call) == 0)
+ return (TC_NOTPERMITTED);
+
+ lock_Status();
+ ptr = findStatus(taskId);
+ if (ptr) {
+- /* strcpy(statusPtr->status, ptr->status); */
+-
+ strcpy(statusPtr->taskName, ptr->taskName);
+ strcpy(statusPtr->volumeName, ptr->volumeName);
+ statusPtr->taskId = ptr->taskId;
+@@ -196,6 +195,7 @@ SScanStatus(struct rx_call *call, afs_uint32 *taskId,
+ statusP ptr = 0;
+ dlqlinkP dlqPtr;
+
++ memset(statusPtr, 0, sizeof(*statusPtr));
+ if (callPermitted(call) == 0)
+ return (TC_NOTPERMITTED);
+
+diff --git a/src/kauth/kaprocs.c b/src/kauth/kaprocs.c
+index 7298b86..8584ad3 100644
+--- a/src/kauth/kaprocs.c
++++ b/src/kauth/kaprocs.c
+@@ -1693,6 +1693,7 @@ kamListEntry(struct rx_call *call,
+ afs_int32 caller;
+ struct kaentry tentry;
+
++ memset(name, 0, sizeof(*name));
+ COUNT_REQ(ListEntry);
+ if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
+ return code;
+diff --git a/src/ptserver/ptprocs.c b/src/ptserver/ptprocs.c
+index f9f48fc..2303c73 100644
+--- a/src/ptserver/ptprocs.c
++++ b/src/ptserver/ptprocs.c
+@@ -687,7 +687,7 @@ idToName(struct rx_call *call, idlist *aid, namelist *aname)
+ return 0;
+ if (size < 0 || size > INT_MAX / PR_MAXNAMELEN)
+ return PRTOOMANY;
+- aname->namelist_val = (prname *) malloc(size * PR_MAXNAMELEN);
++ aname->namelist_val = (prname *) calloc(size, PR_MAXNAMELEN);
+ aname->namelist_len = 0;
+ if (aname->namelist_val == 0)
+ return PRNOMEM;
+@@ -1647,6 +1647,7 @@ put_prentries(struct prentry *tentry, prentries *bulkentries)
+ entry = (struct prlistentries *)bulkentries->prentries_val;
+ entry += bulkentries->prentries_len;
+
++ memset(entry, 0, sizeof(*entry));
+ entry->flags = tentry->flags >> PRIVATE_SHIFT;
+ if (entry->flags == 0) {
+ entry->flags =
+@@ -1661,7 +1662,6 @@ put_prentries(struct prentry *tentry, prentries *bulkentries)
+ entry->nusers = tentry->nusers;
+ entry->count = tentry->count;
+ strncpy(entry->name, tentry->name, PR_MAXNAMELEN);
+- memset(entry->reserved, 0, sizeof(entry->reserved));
+ bulkentries->prentries_len++;
+ return 0;
+ }
+diff --git a/src/ubik/vote.c b/src/ubik/vote.c
+index 13af885..f7bef1a 100644
+--- a/src/ubik/vote.c
++++ b/src/ubik/vote.c
+@@ -406,6 +406,7 @@ SVOTE_Debug(struct rx_call * rxcall, struct ubik_debug * aparm)
+ /* fill in the basic debug structure. Note the the RPC protocol transfers,
+ * integers in host order. */
+
++ memset(aparm, 0, sizeof(*aparm));
+ aparm->now = FT_ApproxTime();
+ aparm->lastYesTime = ubik_lastYesTime;
+ aparm->lastYesHost = ntohl(lastYesHost);
+diff --git a/src/volser/volprocs.c b/src/volser/volprocs.c
+index 90346b8..10f2955 100644
+--- a/src/volser/volprocs.c
++++ b/src/volser/volprocs.c
+@@ -432,6 +432,7 @@ SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
+ struct diskPartition64 *dp = (struct diskPartition64 *)
+ malloc(sizeof(struct diskPartition64));
+
++ memset(partition, 0, sizeof(*partition));
+ code = VolPartitionInfo(acid, pname, dp);
+ if (!code) {
+ strncpy(partition->name, dp->name, 32);
+@@ -451,6 +452,7 @@ SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
+ {
+ afs_int32 code;
+
++ memset(partition, 0, sizeof(*partition));
+ code = VolPartitionInfo(acid, pname, partition);
+ osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
+ return code;
+@@ -2848,6 +2850,7 @@ VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
+ goto done; /*no active transactions */
+ for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
+ nt = tt->next;
++ memset(pntr, 0, sizeof(*pntr));
+ VTRANS_OBJ_LOCK(tt);
+ pntr->tid = tt->tid;
+ pntr->time = tt->time;