[OpenAFS-devel] IBM public license code (from OpenAFS) in samba/examples/nss ok?

Volker.Lendecke@SerNet.DE Volker.Lendecke@SerNet.DE
Thu, 26 Aug 2004 16:29:39 +0200


--xgyAXRrhYN0wYx8y
Content-Type: multipart/mixed; boundary="7AUc2qLy4jB3hD7Z"
Content-Disposition: inline


--7AUc2qLy4jB3hD7Z
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Hi!

Attached find a patch to Samba that implements a rather AFS-specific thing:=
 A
proxy that speaks the AFS ptserver protocol as a server, and redirects the
queries to a locally running winbind. I'd like to commit that to Samba, so =
that
I don't have to patch my customer's special RPM.

The problem are the 3 files ptint.xg and ptopcodes.h which are rather verba=
tim
copies from OpenAFS. ptint.xg is the AFS counterpart of an IDL file,
ptopcodes.h is just are constants. Probably I would have been able to repro=
duce
them from textual documentation, but esp. for the IDL file this is somewhat
nasty.

They are licensed under the IBM public license, as the comment states:=20

/*
 * Copyright 2000, International Business Machines Corporation and others.
 * All Rights Reserved.
 *
 * This software has been released under the terms of the IBM Public
 * License.  For details, see the LICENSE file in the top-level source
 * directory or online at http://www.openafs.org/dl/license10.html
 */

I don't understand the legal stuff enough to be really sure it is ok to che=
ck
this into a GPL project.

Would it be possible to add these files with a special comment? Is it possi=
ble
to distribute them at all?

What do you think? Would it be possible to get an "official" answer from IB=
M?
(duck)...

Volker

--7AUc2qLy4jB3hD7Z
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="samba3-ptproxy.diff"
Content-Transfer-Encoding: quoted-printable

diff -urN ../samba-3.0.4-orig/examples/nss/Makefile examples/nss/Makefile
--- ../samba-3.0.4-orig/examples/nss/Makefile	1970-01-01 01:00:00.000000000=
 +0100
+++ examples/nss/Makefile	2004-07-02 11:05:48.000000000 +0200
@@ -0,0 +1,29 @@
+CPPFLAGS=3D-I/usr/include/afs
+CFLAGS=3D-Wall -g
+
+LIBDIR=3D/usr/lib/afs
+LIBS=3D${LIBDIR}/libcom_err.a ${LIBDIR}/librxkad.a ${LIBDIR}/librx.a
+LIBS+=3D${LIBDIR}/liblwp.a ${LIBDIR}/libuafs.a ${LIBDIR}/libafsrpc.a -lcry=
pto
+
+all: wbtest ptproxy
+
+wbtest: wbtest.o nss_winbind.o
+	gcc -o wbtest -ldl $^=20
+
+clean:
+	rm -f *.o ptproxy wbtest ptint.cs.c ptint.cs ptint.h ptint.ss.c
+	rm -f ptint.xdr.c
+
+ptproxy.o: ptproxy.c nss_winbind.h
+
+ptproxy: ptint.cs.o ptint.ss.o ptint.xdr.o ptproxy.o nss_winbind.o
+	gcc -o ptproxy $^ ${LIBS} -lresolv
+
+ptint.cs.c ptint.h ptint.ss.c ptint.xdr.c: ptint.xg ptopcodes.h
+	rxgen ptint.xg
+
+ptpclient: ptpclient.o ptint.cs.o ptint.xdr.o
+	gcc -o ptpclient ptpclient.o ptint.cs.o ptint.xdr.o ${LIBS}
+
+wb_common.o: wb_common.c
+	gcc -O2 -Wall -c wb_common.c -o wb_common.o
diff -urN ../samba-3.0.4-orig/examples/nss/nss_winbind.c examples/nss/nss_w=
inbind.c
--- ../samba-3.0.4-orig/examples/nss/nss_winbind.c	2004-04-04 09:38:04.0000=
00000 +0200
+++ examples/nss/nss_winbind.c	2004-07-02 11:05:48.000000000 +0200
@@ -8,6 +8,16 @@
    not need to give any attribution.
 */
=20
+/*
+   compile like this:
+
+      cc -o wbtest wbtest.c -ldl
+
+   and run like this:
+
+      ./wbtest /lib/libnss_winbind.so
+*/
+
 #define _GNU_SOURCE
=20
 #include <stdio.h>
@@ -146,6 +156,99 @@
 	return 0;
 }
=20
+/*
+  make a getgrent call.=20
+  Return 0 on success and -1 on error
+*/
+int nss_getgrent(struct nss_state *nss, struct group *grp)
+{
+	enum nss_status (*_nss_getgrent_r)(struct group *, char *,=20
+					   size_t , int *);
+	enum nss_status status;
+	int nss_errno =3D 0;
+
+	static char *buf =3D NULL;
+	static int bufsize =3D 512;
+
+	_nss_getgrent_r =3D find_fn(nss, "getgrent_r");
+
+	if (!_nss_getgrent_r) {
+		return -1;
+	}
+
+ again:
+	if (buf =3D=3D NULL)
+		buf =3D malloc(bufsize);
+
+	if (buf =3D=3D NULL) {
+	        errno =3D ENOMEM;
+		return -1;
+	}
+
+	status =3D _nss_getgrent_r(grp, buf, bufsize, &nss_errno);
+
+	if (status =3D=3D NSS_STATUS_TRYAGAIN) {
+		free(buf);
+		buf =3D NULL;
+		bufsize *=3D 2;
+		if (bufsize > 1048576) {
+			/* More than a megabyte for a group -- don't know.. */
+			errno =3D ENOMEM;
+			return -1;
+		}
+		goto again;
+	}
+
+	if (status =3D=3D NSS_STATUS_NOTFOUND) {
+		errno =3D ENOENT;
+		return -1;
+	}
+	if (status !=3D NSS_STATUS_SUCCESS) {
+		errno =3D nss_errno;
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+  make a setgrent call.=20
+  Return 0 on success and -1 on error
+*/
+int nss_setgrent(struct nss_state *nss)
+{
+	enum nss_status (*_nss_setgrent)(void) =3D find_fn(nss, "setgrent");
+	enum nss_status status;
+	if (!_nss_setgrent) {
+		return -1;
+	}
+	status =3D _nss_setgrent();
+	if (status !=3D NSS_STATUS_SUCCESS) {
+		errno =3D EINVAL;
+		return -1;
+	}
+	return 0;
+}
+
+/*
+  make a endgrent call.=20
+  Return 0 on success and -1 on error
+*/
+int nss_endgrent(struct nss_state *nss)
+{
+	enum nss_status (*_nss_endgrent)(void) =3D find_fn(nss, "endgrent");
+	enum nss_status status;
+	if (!_nss_endgrent) {
+		return -1;
+	}
+	status =3D _nss_endgrent();
+	if (status !=3D NSS_STATUS_SUCCESS) {
+		errno =3D EINVAL;
+		return -1;
+	}
+	return 0;
+}
+
=20
 /*
   convert a name to a SID
diff -urN ../samba-3.0.4-orig/examples/nss/nss_winbind.h examples/nss/nss_w=
inbind.h
--- ../samba-3.0.4-orig/examples/nss/nss_winbind.h	2004-04-04 09:38:04.0000=
00000 +0200
+++ examples/nss/nss_winbind.h	2004-07-02 11:05:48.000000000 +0200
@@ -50,6 +50,24 @@
 int nss_endpwent(struct nss_state *nss);
=20
 /*
+  make a getgrent call.=20
+  Return 0 on success and -1 on error
+*/
+int nss_getgrent(struct nss_state *nss, struct group *grp);
+
+/*
+  make a setgrent call.=20
+  Return 0 on success and -1 on error
+*/
+int nss_setgrent(struct nss_state *nss);
+
+/*
+  make a endgrent call.=20
+  Return 0 on success and -1 on error
+*/
+int nss_endgrent(struct nss_state *nss);
+
+/*
   convert a name to a SID
   caller frees
   Return 0 on success and -1 on error
diff -urN ../samba-3.0.4-orig/examples/nss/ptint.cs.h examples/nss/ptint.cs=
.h
--- ../samba-3.0.4-orig/examples/nss/ptint.cs.h	1970-01-01 01:00:00.0000000=
00 +0100
+++ examples/nss/ptint.cs.h	2004-07-02 11:05:48.000000000 +0200
@@ -0,0 +1,48 @@
+#include "ptint.h"
+
+int PR_INewEntry(struct rx_connection *call, char name[PR_MAXNAMELEN],
+		 afs_int32 id, afs_int32 oid);
+int PR_WhereIsIt(struct rx_connection *call, afs_int32 id,
+		 afs_int32 *ps);
+int PR_DumpEntry(struct rx_connection *call, afs_int32 pos,
+		 struct prdebugentry *entry);
+int PR_AddToGroup(struct rx_connection *call, afs_int32 uid,
+		  afs_int32 gid);
+int PR_NameToID(struct rx_connection *call, namelist *nlist,
+		idlist *ilist);
+int PR_IDToName(struct rx_connection *call, idlist *ilist,
+		namelist *nlist);
+int PR_Delete(struct rx_connection *call, afs_int32 id);
+int PR_RemoveFromGroup(struct rx_connection *call, afs_int32 id,
+		       afs_int32 gid);
+int PR_GetCPS(struct rx_connection *call, afs_int32 id, prlist *elist,
+	      afs_int32 *over);
+int PR_NewEntry(struct rx_connection *call, char name[PR_MAXNAMELEN],
+		afs_int32 flag, afs_int32 oid, afs_int32 *id);
+int PR_ListMax(struct rx_connection *call, afs_int32 *uid,
+	       afs_int32 *gid);
+int PR_SetMax(struct rx_connection *call, afs_int32 id, afs_int32 gflag);
+int PR_ListEntry(struct rx_connection *call, afs_int32 id,
+		 struct prcheckentry *entry);
+int PR_ChangeEntry(struct rx_connection *call, afs_int32 id,
+		   char name[PR_MAXNAMELEN], afs_int32 oid,
+		   afs_int32 newid);
+int PR_ListElements(struct rx_connection *call, afs_int32 id,
+		    prlist *elist, afs_int32 *over);
+int PR_IsAMemberOf(struct rx_connection *call, afs_int32 uid,
+		   afs_int32 gid, afs_int32 *flag);
+int PR_SetFieldsEntry(struct rx_connection *call, afs_int32 id,
+		      afs_int32 mask, afs_int32 flags,
+		      afs_int32 ngroups, afs_int32 nusers,
+		      afs_int32 spare1, afs_int32 spare2);
+int PR_ListOwned(struct rx_connection *call, afs_int32 id,
+		 prlist *elist, afs_int32 *lastp);
+int PR_GetCPS2(struct rx_connection *call, afs_int32 id, afs_int32 host,
+	       prlist *elist, afs_int32 *over);
+int PR_GetHostCPS(struct rx_connection *call, afs_int32 host,
+		  prlist *elist, afs_int32 *over);
+int PR_UpdateEntry(struct rx_connection *call, afs_int32 id,
+		   char name[PR_MAXNAMELEN], PrUpdateEntry *uentry);
+int PR_ListEntries(struct rx_connection *call,  afs_int32 flags,
+		   afs_int32 startindex, prentries *bulkentries,
+		   afs_int32 *nextstartindex);
diff -urN ../samba-3.0.4-orig/examples/nss/ptint.xg examples/nss/ptint.xg
--- ../samba-3.0.4-orig/examples/nss/ptint.xg	1970-01-01 01:00:00.000000000=
 +0100
+++ examples/nss/ptint.xg	2004-07-02 11:05:48.000000000 +0200
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2000, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ *=20
+ * This software has been released under the terms of the IBM Public
+ * License.  For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+package PR_
+prefix S
+statindex 8
+
+#include "ptopcodes.h"
+
+const PRSUCCESS=3D0;
+
+const PR_MAXNAMELEN=3D64;
+const PR_MAXGROUPS=3D5000;
+const PR_MAXLIST=3D5000;
+const PRSIZE=3D10;
+const COSIZE=3D39;
+
+struct prdebugentry {
+	afs_int32 flags;
+	afs_int32 id;
+	afs_int32 cellid;
+	afs_int32 next;
+	afs_int32 reserved[5];
+	afs_int32 entries[PRSIZE];
+	afs_int32 nextID;
+	afs_int32 nextname;
+	afs_int32 owner;
+	afs_int32 creator;
+	afs_int32 ngroups;
+	afs_int32 nusers;
+	afs_int32 count;
+	afs_int32 instance;
+	afs_int32 owned;
+	afs_int32 nextOwned;
+	afs_int32 parent;
+	afs_int32 sibling;
+	afs_int32 child;
+	char name[PR_MAXNAMELEN];
+};
+
+struct prcheckentry {
+        afs_int32 flags;
+	afs_int32 id;
+	afs_int32 owner;
+	afs_int32 creator;
+	afs_int32 ngroups;
+	afs_int32 nusers;
+	afs_int32 count;
+	afs_int32 reserved[5];
+	char name[PR_MAXNAMELEN];
+};=09
+
+struct prlistentries {
+        afs_int32 flags;
+	afs_int32 id;
+	afs_int32 owner;
+	afs_int32 creator;
+	afs_int32 ngroups;
+	afs_int32 nusers;
+	afs_int32 count;
+	afs_int32 reserved[5];
+	char name[PR_MAXNAMELEN];
+};=09
+
+struct PrUpdateEntry {
+	afs_uint32 Mask;
+        afs_int32 flags;
+	afs_int32 id;
+	afs_int32 owner;
+	afs_int32 creator;
+	afs_int32 ngroups;
+	afs_int32 nusers;
+	afs_int32 count;
+	afs_int32 reserved[5];
+	char name[PR_MAXNAMELEN];
+};=09
+
+/* struct VldbUpdateEntry Mask bit values */
+const	PRUPDATE_NAME	=3D	0x0001;
+const	PRUPDATE_ID	=3D	0x0002;
+const	PRUPDATE_FLAGS	=3D	0x0004;
+const	PRUPDATE_NAMEHASH=3D	0x0008;
+const	PRUPDATE_IDHASH =3D	0x0010;
+
+/* These bits are used when calling SetFieldsEntry. */
+%#define PR_SF_ALLBITS   0xff		/* set all access bits */
+%#define PR_SF_NGROUPS (1<<31)		/* set field limiting group creation */
+%#define PR_SF_NUSERS  (1<<30)		/*  "  "  foreign users  "  */
+
+typedef char prname[PR_MAXNAMELEN];
+typedef prname namelist<>;
+typedef afs_int32 idlist<>;
+typedef afs_int32 prlist<>;
+typedef prlistentries prentries<>;
+
+INewEntry(
+  IN string name<PR_MAXNAMELEN>,
+  IN afs_int32 id,
+  IN afs_int32 oid
+) =3D PRINEWUSER;
+
+WhereIsIt(
+  IN afs_int32 id,
+  OUT afs_int32 *ps
+) =3D PRWHEREISIT;
+
+DumpEntry(
+  IN afs_int32 pos,
+  OUT struct prdebugentry *entry
+) =3D PRDUMPENTRY;
+
+AddToGroup(
+  IN afs_int32 uid,
+  IN afs_int32 gid
+)=3DPRADDTOGROUP;
+
+NameToID(
+  IN namelist *nlist,
+  OUT idlist *ilist
+)=3DPRNAMETOID;
+
+IDToName(
+  IN idlist *ilist,
+  OUT namelist *nlist
+) =3DPRIDTONAME;
+
+Delete(
+  IN afs_int32 id
+)=3DPRDELETE;
+
+RemoveFromGroup(
+  IN afs_int32 id,
+  IN afs_int32 gid
+)=3DPRREMOVEFROMGROUP;
+
+GetCPS(
+  IN afs_int32 id,
+  OUT prlist *elist,
+  OUT afs_int32 *over
+)=3DPRGETCPS;
+
+NewEntry(
+  IN string name<PR_MAXNAMELEN>,
+  afs_int32 flag,
+  afs_int32 oid,
+  OUT afs_int32 *id
+)=3DPRNEWENTRY;
+
+ListMax(
+  OUT afs_int32 *uid,
+  afs_int32 *gid
+)=3DPRLISTMAX;
+
+SetMax(
+  IN afs_int32 id,
+  afs_int32 gflag
+)=3DPRSETMAX;
+
+ListEntry(
+  IN afs_int32 id,
+  OUT struct prcheckentry *entry
+) =3D PRLISTENTRY;
+
+ChangeEntry(
+  IN afs_int32 id,
+  IN string name<PR_MAXNAMELEN>,
+  IN afs_int32 oid,
+  IN afs_int32 newid
+) =3D PRCHANGEENTRY;
+
+ListElements(
+  IN afs_int32 id,
+  OUT prlist *elist,
+  OUT afs_int32 *over
+)=3DPRLISTELEMENTS;
+
+IsAMemberOf(
+  IN afs_int32 uid,
+  IN afs_int32 gid,
+  OUT afs_int32 *flag
+)=3DPRISAMEMBEROF;
+
+SetFieldsEntry(
+  IN afs_int32 id,
+  IN afs_int32 mask,
+  IN afs_int32 flags,
+  IN afs_int32 ngroups,
+  IN afs_int32 nusers,
+  IN afs_int32 spare1,
+  IN afs_int32 spare2
+) =3D PRSETFIELDSENTRY;
+
+ListOwned(
+  IN afs_int32 id,
+  OUT prlist *elist,
+  INOUT afs_int32 *lastp
+) =3D PRLISTOWNED;
+
+GetCPS2(
+  IN afs_int32 id,
+  IN afs_int32 host,
+  OUT prlist *elist,
+  OUT afs_int32 *over
+)=3DPRGETCPS2;
+
+GetHostCPS(
+  IN afs_int32 host,
+  OUT prlist *elist,
+  OUT afs_int32 *over
+)=3DPRGETHOSTCPS;
+
+UpdateEntry(
+  IN afs_int32 id,
+  IN string name<PR_MAXNAMELEN>,
+  IN PrUpdateEntry *uentry
+) =3D PRUPDATEENTRY;
+
+ListEntries(
+  IN afs_int32      flags,
+  IN afs_int32      startindex,
+  OUT prentries *bulkentries,
+  OUT afs_int32     *nextstartindex
+) =3D PRLISTENTRIES;
diff -urN ../samba-3.0.4-orig/examples/nss/ptopcodes.h examples/nss/ptopcod=
es.h
--- ../samba-3.0.4-orig/examples/nss/ptopcodes.h	1970-01-01 01:00:00.000000=
000 +0100
+++ examples/nss/ptopcodes.h	2004-07-02 11:05:48.000000000 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ *=20
+ * This software has been released under the terms of the IBM Public
+ * License.  For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+#define LOWEST_OPCODE 500
+#define PRINEWUSER  500
+#define PRWHEREISIT 501
+#define PRDUMPENTRY 502
+#define PRADDTOGROUP 503
+#define PRNAMETOID 504
+#define PRIDTONAME 505
+#define PRDELETE 506
+#define PRREMOVEFROMGROUP 507
+#define PRGETCPS 508
+#define PRNEWENTRY 509
+#define PRLISTMAX 510
+#define PRSETMAX 511
+#define PRLISTENTRY 512
+#define PRCHANGEENTRY 513
+#define PRLISTELEMENTS 514
+#define PRISAMEMBEROF 515
+#define PRSETFIELDSENTRY 516
+#define PRLISTOWNED 517
+#define PRGETCPS2 518
+#define PRGETHOSTCPS 519
+#define PRUPDATEENTRY 520
+#define PRLISTENTRIES 521
+#define HIGHEST_OPCODE 521
+
diff -urN ../samba-3.0.4-orig/examples/nss/ptproxy.c examples/nss/ptproxy.c
--- ../samba-3.0.4-orig/examples/nss/ptproxy.c	1970-01-01 01:00:00.00000000=
0 +0100
+++ examples/nss/ptproxy.c	2004-07-02 11:07:16.000000000 +0200
@@ -0,0 +1,879 @@
+#define _GNU_SOURCE
+
+#include <openssl/des.h>
+#include <string.h>
+#include <ctype.h>
+#include <afs/ptint.h>
+#include <afs/pterror.h>
+#include <afs/prserver.h>
+#include <afs/dirpath.h>
+#include <rx/rxkad.h>
+#include <afs/cellconfig.h>
+#include <nss.h>
+#include "ptint.cs.h"
+#include "nss_winbind.h"
+#include <errno.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define _GNU_SOURCE
+#include <getopt.h>
+
+static struct nss_state state;
+
+static char *domain_sid;
+
+char *administrators_sid =3D NULL;
+char *anyuser_sid =3D NULL;
+char *authuser_sid =3D NULL;
+
+#define DOMADM_RID 512
+#define DOMGUEST_RID 514
+
+static char SPACE_REPLACEMENT=3D'%';
+
+#ifdef __GNUC__
+/** Use gcc attribute to check printf fns.  a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument.  **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a=
2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+
+static void do_debug(const char *, ...) PRINTF_ATTRIBUTE(1,2);
+static int DEBUGLEVEL;
+#define DEBUGLVL(level) ((level) <=3D DEBUGLEVEL)
+#define DEBUG(level, body) do { if (DEBUGLVL(level)) do_debug body; } whil=
e (0)
+
+/*
+  the backend for debug messages. Note that the DEBUG() macro has already
+  ensured that the log level has been met before this is called
+*/
+void do_debug(const char *format, ...)
+{
+        va_list ap;
+        va_start(ap, format);
+        vsyslog(LOG_INFO, format, ap);
+        va_end(ap);
+}
+
+afs_int32 SPR_INewEntry(struct rx_call *call, char name[PR_MAXNAMELEN],
+			afs_int32 id, afs_int32 oid)
+{
+	DEBUG(10, ("SPR_INewEntry called\n"));
+	return PRPERM;
+}
+
+afs_int32 SPR_WhereIsIt(struct rx_call *call, afs_int32 id,
+			afs_int32 *ps)
+{
+	DEBUG(10, ("SPR_WhereIsIt called\n"));
+	return PRNOENT;
+}
+
+afs_int32 SPR_DumpEntry(struct rx_call *call, afs_int32 pos,
+			struct prdebugentry *entry)
+{
+	DEBUG(10, ("SPR_DumpEntry called\n"));
+	return PRPERM;
+}
+
+afs_int32 SPR_AddToGroup(struct rx_call *call, afs_int32 uid, afs_int32 gi=
d)
+{
+	DEBUG(10, ("SPR_AddToGroup called\n"));
+	return PRPERM;
+}
+
+static afs_int32 wb_SIDToID(const char *sid)
+{
+	int res;
+	uid_t uid;
+	gid_t gid;
+
+	DEBUG(10, ("wb_SIDToID: sid %s\n", sid));
+
+	/* Check for the domain administrators group, map them to
+	 * SYSADMINID. */
+
+	if (strcasecmp(sid, administrators_sid) =3D=3D 0) {
+		DEBUG(10, ("wb_SIDToID: found domain admins\n"));
+		return SYSADMINID;
+	}
+
+	if (strcasecmp(sid, anyuser_sid) =3D=3D 0) {
+		DEBUG(10, ("wb_SIDToID: found anyuser\n"));
+		return ANYUSERID;
+	}
+	=09
+	if (strcasecmp(sid, authuser_sid) =3D=3D 0) {
+		DEBUG(10, ("wb_SIDToID: found authuser\n"));
+		return AUTHUSERID;
+	}
+
+	res =3D nss_sidtouid(&state, sid, &uid);
+
+	DEBUG(10, ("wb_SIDToID: nss_sidtouid returned %d, %s\n",
+		   res, strerror(errno)));
+
+	if (res =3D=3D 0) {
+		DEBUG(10, ("-> uid %d\n", uid));
+		return (afs_int32)uid;
+	}
+
+	res =3D nss_sidtogid(&state, sid, &gid);
+
+	DEBUG(10, ("wb_SIDToID: nss_sidtogid returned %d, %s\n",
+		   res, strerror(errno)));
+
+	if (res =3D=3D 0) {
+		DEBUG(10, ("-> gid %d\n", gid));
+		return (afs_int32)(-gid);
+	}
+
+	DEBUG(10, ("-> ANONYMOUSID\n"));
+	return ANONYMOUSID;
+}
+
+static afs_int32 wb_NameToID(prname name)
+{
+	int res;
+	afs_int32 result;
+
+	char *sid;
+
+	char *translated_name;
+	char *c;
+
+	DEBUG(10, ("wb_NameToID: %s\n", name));
+
+	if (strcasecmp(name, "system:administrators") =3D=3D 0)
+		return SYSADMINID;
+
+	if (strcasecmp(name, "system:anyuser") =3D=3D 0)
+		return ANYUSERID;
+
+	if (strcasecmp(name, "system:authuser") =3D=3D 0)
+		return AUTHUSERID;
+
+	translated_name =3D strdup(name);
+
+	if (translated_name =3D=3D NULL) {
+		DEBUG(10, ("wb_NameToID: no memory\n"));
+		return ANONYMOUSID;
+	}
+
+	for (c=3Dtranslated_name; *c; c+=3D1) {
+		if (*c =3D=3D SPACE_REPLACEMENT)
+			*c =3D ' ';
+	}
+
+	res =3D nss_nametosid(&state, translated_name, &sid);
+
+	free(translated_name);
+
+	if (res !=3D 0) {
+		DEBUG(10, ("nss_nametosid not successful: %s\n",
+			   strerror(errno)));
+		return ANONYMOUSID;
+	}
+
+	result =3D wb_SIDToID(sid);
+
+	DEBUG(10, ("wb_NameToID: %s -> %s -> %d\n",
+		   name, sid, (int)result));
+
+	free(sid);
+
+	return result;
+}
+
+afs_int32 SPR_NameToID(struct rx_call *call, namelist *nlist, idlist *ilis=
t)
+{
+	int i;
+
+	DEBUG(10, ("SPR_NameToID called\n"));
+
+	ilist->idlist_len =3D nlist->namelist_len;
+
+	if (ilist->idlist_len =3D=3D 0) {
+		DEBUG(10, ("No names\n"));
+		return 0;
+	}
+
+	if (ilist->idlist_len < 0) {
+		DEBUG(10, ("Too many names\n"));
+		return PRTOOMANY;
+	}
+
+	ilist->idlist_val =3D malloc(sizeof(*ilist->idlist_val) *
+				   ilist->idlist_len);
+
+	if (ilist->idlist_val =3D=3D NULL) {
+		DEBUG(10, ("No memory\n"));
+		return PRNOMEM;
+	}
+
+	for (i=3D0; i<nlist->namelist_len; i++) {
+		ilist->idlist_val[i] =3D wb_NameToID(nlist->namelist_val[i]);
+		DEBUG(10, ("ID: %d\n", (int)ilist->idlist_val[i]));
+	}
+
+	return PRSUCCESS;
+}
+
+static int wb_IDToSID(afs_int32 id, char **sid)
+{
+	int res =3D 0;
+
+	DEBUG(10, ("wb_IDToSID: %d\n", (int)id));
+
+	if (id =3D=3D SYSADMINID) {
+		*sid =3D strdup(administrators_sid);
+	} else if (id =3D=3D ANYUSERID) {
+		*sid =3D strdup(anyuser_sid);
+	} else if (id =3D=3D AUTHUSERID) {
+		*sid =3D strdup(authuser_sid);
+	} else if (id > 0) {
+		/* Normal users */
+		res =3D nss_uidtosid(&state, id, sid);
+	} else {
+		/* Normal groups */
+		res =3D nss_gidtosid(&state, -id, sid);
+	}
+
+	DEBUG(10, ("wb_IDToSID: %d -> %s\n", (int)id, *sid));
+
+	return res;
+}
+
+static void push_winname(prname name, char *winname, afs_int32 id)
+{
+	if (strlen(winname) >=3D PR_MAXNAMELEN) {
+		snprintf(name, PR_MAXNAMELEN-1, "nametoolong:%d", (int)id);
+		return;
+	}
+
+	memset(name, 0, PR_MAXNAMELEN);
+	strncpy(name, winname, PR_MAXNAMELEN-1);
+
+	for (winname =3D name; *winname; winname +=3D 1) {
+		if (*winname =3D=3D ' ')
+			*winname =3D SPACE_REPLACEMENT;
+	}
+}
+
+static void wb_IDToName(afs_int32 id, prname name)
+{
+	int res =3D 0;
+	char *sid;
+	char *winname;
+
+	memset(name, 0, PR_MAXNAMELEN);
+
+	switch(id) {
+	case SYSADMINID:
+		strncpy(name, "system:administrators", PR_MAXNAMELEN-1);
+		return;
+	case ANYUSERID:
+		strncpy(name, "system:anyuser", PR_MAXNAMELEN-1);
+		return;
+	case AUTHUSERID:
+		strncpy(name, "system:authuser", PR_MAXNAMELEN-1);
+		return;
+	}
+
+	res =3D wb_IDToSID(id, &sid);
+
+	DEBUG(10, ("wb_IDToName: sid =3D %s, res =3D %d\n", sid, res));
+
+	if (res !=3D 0) {
+		snprintf(name, PR_MAXNAMELEN-1, "%d", (int)id);
+		return;
+	}
+
+	res =3D nss_sidtoname(&state, sid, &winname);
+
+	free(sid);
+
+	if (res !=3D 0) {
+		DEBUG(10, ("wb_IDToName: nss_sidtoname failed: %s\n",
+			   strerror(errno)));
+		snprintf(name, PR_MAXNAMELEN-1, "%d", (int)id);
+		return;
+	}
+
+	push_winname(name, winname, id);
+
+	DEBUG(10, ("wb_IDToName: %d -> %s\n", (int)id, name));
+=09
+	return;
+}=09
+
+afs_int32 SPR_IDToName(struct rx_call *call, idlist *ilist, namelist *nlis=
t)
+{
+	int i;
+	DEBUG(10, ("SPR_IDToName called\n"));
+
+	nlist->namelist_len =3D ilist->idlist_len;
+
+	if (nlist->namelist_len =3D=3D 0) {
+		DEBUG(10, ("SPR_IDToName: no names\n"));
+		return 0;
+	}
+
+	if (nlist->namelist_len < 0) {
+		DEBUG(10, ("SPR_IDToName: too many names\n"));
+		return PRTOOMANY;
+	}
+
+	nlist->namelist_val =3D malloc(nlist->namelist_len * PR_MAXNAMELEN);
+
+	if (nlist->namelist_val =3D=3D NULL) {
+		DEBUG(10, ("SPR_IDToName: no memory\n"));
+		return PRNOMEM;
+	}
+
+	for (i=3D0; i<nlist->namelist_len; i++)
+		wb_IDToName(ilist->idlist_val[i], nlist->namelist_val[i]);
+
+	return PRSUCCESS;
+}
+
+afs_int32 SPR_Delete(struct rx_call *call, afs_int32 id)
+{
+	DEBUG(10, ("SPR_Delete called\n"));
+	return PRPERM;
+}
+
+afs_int32 SPR_RemoveFromGroup(struct rx_call *call, afs_int32 id,
+			      afs_int32 gid)
+{
+	DEBUG(10, ("SPR_RemoveFromGroup called\n"));
+	return PRPERM;
+}
+
+/* Helper function for sorting in GetCPS */
+
+static int compare_ids(const void *x, const void *y)
+{
+	afs_int32 *a =3D (afs_int32 *)x;
+	afs_int32 *b =3D (afs_int32 *)y;
+
+	if (*a > *b) return 1;
+	if (*a < *b) return -1;
+	return 0;
+}
+
+afs_int32 SPR_GetCPS(struct rx_call *call, afs_int32 id, prlist *elist,
+		     afs_int32 *over)
+{
+	afs_int32 result;
+	int i, res;
+
+	char *sid;
+	char **sids;
+
+	DEBUG(10, ("SPR_GetCPS called: %d\n", (int)id));
+
+	if ((id =3D=3D ANYUSERID) || (id =3D=3D ANONYMOUSID)) {
+		elist->prlist_len =3D 1;
+		elist->prlist_val =3D malloc(sizeof(afs_int32));
+
+		if (elist->prlist_val =3D=3D NULL) {
+			DEBUG(10, ("SPR_GetCPS: no memory\n"));
+			free(sid);
+			return PRNOMEM;
+		}
+
+		elist->prlist_val[0] =3D id;
+		return PRSUCCESS;
+	}
+
+	res =3D wb_IDToSID(id, &sid);
+
+	if (res !=3D 0) {
+		DEBUG(10, ("SPR_GetCPS: wb_IDToSID failed\n"));
+		return PRNOENT;
+	}
+
+	DEBUG(10, ("UserSID: %s\n", sid));
+
+	elist->prlist_len =3D 3;
+	elist->prlist_val =3D malloc(elist->prlist_len*sizeof(afs_int32));
+
+	if (elist->prlist_val =3D=3D NULL) {
+		DEBUG(10, ("SPR_GetCPS: no memory\n"));
+		free(sid);
+		return PRNOMEM;
+	}
+
+	elist->prlist_val[0] =3D AUTHUSERID;
+	elist->prlist_val[1] =3D ANYUSERID;
+	elist->prlist_val[2] =3D id;
+
+	res =3D nss_getusersids(&state, sid, &sids);
+
+	free(sid);
+
+	if (res !=3D 0) {
+		DEBUG(10, ("SPR_GetCPS: nss_getusersids failed\n"));
+		return PRNOMEM;
+	}
+
+	result =3D PRSUCCESS;
+
+	for (i =3D 0; sids[i] !=3D NULL; i +=3D 1) {
+
+		afs_int32 id =3D wb_SIDToID(sids[i]);
+
+		if (id !=3D ANONYMOUSID) {
+			elist->prlist_len +=3D 1;
+			elist->prlist_val =3D realloc(elist->prlist_val,
+						    elist->prlist_len *
+						    sizeof(afs_int32));
+
+			if (elist->prlist_val =3D=3D NULL) {
+				result =3D PRNOMEM;
+				break;
+			}
+
+			elist->prlist_val[elist->prlist_len-1] =3D id;
+		}
+	}
+
+	for (i=3D0; sids[i] !=3D NULL; i++) {
+		free(sids[i]);
+	}
+
+	free(sids);
+
+	if (result =3D=3D PRSUCCESS) {
+		qsort(elist->prlist_val, elist->prlist_len, sizeof(afs_int32),
+		      compare_ids);
+	}
+
+	return result;
+}
+
+afs_int32 SPR_NewEntry(struct rx_call *call, char name[PR_MAXNAMELEN],
+		       afs_int32 flag, afs_int32 oid, afs_int32 *id)
+{
+	DEBUG(10, ("SPR_NewEntry called\n"));
+	return PRPERM;
+}
+
+afs_int32 SPR_ListMax(struct rx_call *call, afs_int32 *uid, afs_int32 *gid)
+{
+	DEBUG(10, ("SPR_ListMax called\n"));
+	return PRPERM;
+}
+
+afs_int32 SPR_SetMax(struct rx_call *call, afs_int32 id, afs_int32 gflag)
+{
+	DEBUG(10, ("SPR_SetMax called\n"));
+	return PRPERM;
+}
+
+afs_int32 SPR_ListEntry(struct rx_call *call, afs_int32 id,
+			struct prcheckentry *entry)
+{
+	DEBUG(10, ("SPR_ListEntry called\n"));
+
+	entry->flags =3D 0;
+	entry->owner =3D SYSADMINID;
+	entry->id =3D id;
+	wb_IDToName(id, entry->name);
+	entry->creator =3D SYSADMINID;
+	entry->ngroups =3D 0;
+	entry->nusers =3D 0;
+	entry->count =3D 0;
+	memset(entry->reserved, 0, sizeof(entry->reserved));
+
+	return PRSUCCESS;
+}
+
+afs_int32 SPR_ChangeEntry(struct rx_call *call, afs_int32 id,
+			  char name[PR_MAXNAMELEN], afs_int32 oid,
+			  afs_int32 newid)
+{
+	DEBUG(10, ("SPR_ChangeEntry called\n"));
+	return PRPERM;
+}
+
+afs_int32 SPR_ListElements(struct rx_call *call, afs_int32 id,
+			   prlist *elist, afs_int32 *over)
+{
+	DEBUG(10, ("SPR_ListElements called\n"));
+	return PRPERM;
+}
+
+afs_int32 SPR_IsAMemberOf(struct rx_call *call, afs_int32 uid,
+			  afs_int32 gid, afs_int32 *flag)
+{
+	char *usid;
+	char *gsid;
+	char **sids;
+
+	int i;
+
+	DEBUG(10, ("SPR_IsAMemberOf called: uid =3D %d, gid =3D %d\n",
+		   (int)uid, (int)gid));
+
+	if (wb_IDToSID(uid, &usid) !=3D 0) {
+		DEBUG(10, ("SPR_IsAMemberOf: Could not get sid of uid\n"));
+		return PRPERM;
+	}
+
+	if (wb_IDToSID(gid, &gsid) !=3D 0) {
+		DEBUG(10, ("SPR_IsAMemberOf: Could not get sid of gid\n"));
+		free(usid);
+		return PRPERM;
+	}
+
+	if (nss_getusersids(&state, usid, &sids) !=3D 0) {
+		DEBUG(10, ("SPR_IsAMemberOf: Could not get sids\n"));
+		free(usid);
+		free(gsid);
+		return PRPERM;
+	}
+
+	*flag =3D 0;
+	for (i =3D 0; sids[i] !=3D NULL; i +=3D 1) {
+		if (strcmp(gsid, sids[i]) =3D=3D 0) {
+			*flag =3D 1;
+		}
+		free(sids[i]);
+	}
+
+	free(sids);
+	free(usid);
+	free(gsid);
+
+	return PRPERM;
+}
+
+afs_int32 SPR_SetFieldsEntry(struct rx_call *call, afs_int32 id,
+			     afs_int32 mask, afs_int32 flags,
+			     afs_int32 ngroups, afs_int32 nusers,
+			     afs_int32 spare1, afs_int32 spare2)
+{
+	DEBUG(10, ("SPR_SetFieldsEntry called\n"));
+	return PRPERM;
+}
+
+afs_int32 SPR_ListOwned(struct rx_call *call, afs_int32 id,
+			prlist *elist, afs_int32 *lastp)
+{
+	DEBUG(10, ("SPR_ListOwned called\n"));
+	return PRPERM;
+}
+
+afs_int32 SPR_GetCPS2(struct rx_call *call, afs_int32 id, afs_int32 host,
+		      prlist *elist, afs_int32 *over)
+{
+	DEBUG(10, ("SPR_GetCPS2 called\n"));
+	return PRPERM;
+}
+
+afs_int32 SPR_GetHostCPS(struct rx_call *call, afs_int32 host,
+			 prlist *alist, afs_int32 *over)
+{
+        struct in_addr addr;
+	addr.s_addr =3D htonl(host);
+	prname addr_str;
+	afs_uint32 id;
+
+	strncpy(addr_str, inet_ntoa(addr), PR_MAXNAMELEN-1);
+	id =3D wb_NameToID(addr_str);
+
+	/* If the name can't be found, the host needs to be treated as
+	 * ANYUSER */
+	if (id =3D=3D ANONYMOUSID)
+		id =3D ANYUSERID;
+
+	DEBUG(10, ("SPR_GetHostCPS called: %s [%u]\n", addr_str,
+		   (unsigned int)id));
+
+	return SPR_GetCPS(call, id, alist, over);
+}
+
+afs_int32 SPR_UpdateEntry(struct rx_call *call, afs_int32 id,
+			  char name[PR_MAXNAMELEN], PrUpdateEntry *uentry)
+{
+	DEBUG(10, ("SPR_UpdateEntry called\n"));
+	return PRPERM;
+}
+
+static void add_prentry(struct prentries *list,
+			char *name, afs_int32 id, int flags)
+{
+	struct prlistentries *entry;
+
+	DEBUG(10, ("Adding entry [%s], %d\n", name, (int)id));
+
+	list->prentries_val =3D realloc(list->prentries_val,
+				      (list->prentries_len+1) *
+				      sizeof(struct prlistentries));
+	entry =3D &(list->prentries_val[list->prentries_len]);
+
+	memset(entry, 0, sizeof(struct prlistentries));
+	entry->flags =3D flags;
+	entry->id =3D id;
+	entry->owner =3D SYSADMINID;
+	entry->creator =3D SYSADMINID;
+	entry->ngroups =3D 1;
+	entry->nusers =3D 1;
+	entry->count =3D 1;
+	push_winname(entry->name, name, id);
+
+	list->prentries_len +=3D 1;
+}
+
+static struct prentries userlist =3D {0, NULL};
+static struct prentries grouplist =3D {0, NULL};
+
+static void collect_users(void)
+{
+	struct passwd pwd;
+
+	if (userlist.prentries_val !=3D NULL) {
+		free(userlist.prentries_val);
+		userlist.prentries_len =3D 0;
+	}
+
+	if (nss_setpwent(&state) !=3D 0) {
+		DEBUG(1, ("nss_setpwent failed\n"));
+		return;
+	}
+
+	while (nss_getpwent(&state, &pwd) =3D=3D 0) {
+		add_prentry(&userlist, pwd.pw_name, pwd.pw_uid, 0x80);
+	}
+
+	if (nss_endpwent(&state) !=3D 0) {
+		DEBUG(1, ("nss_endpwent failed\n"));
+		return;
+	}
+}=09
+
+static void collect_groups(void)
+{
+	struct group grp;
+
+	if (nss_setgrent(&state) !=3D 0) {
+		DEBUG(1, ("nss_setgrent failed\n"));
+		return;
+	}
+
+	while (nss_getgrent(&state, &grp) =3D=3D 0) {
+		add_prentry(&grouplist, grp.gr_name, -grp.gr_gid, 0x88);
+	}
+
+	if (nss_endgrent(&state) !=3D 0) {
+		DEBUG(1, ("nss_endgrent failed\n"));
+		return;
+	}
+}=09
+
+/* From ptserver.h */
+#define PRUSERS  0x1
+#define PRGROUPS 0x2
+#define MAXENTRIES 500
+
+afs_int32 SPR_ListEntries(struct rx_call *call,  afs_int32 flags,
+			  afs_int32 startindex, prentries *bulkentries,
+			  afs_int32 *nextstartindex)
+{
+	struct prentries *list;
+	int entries_thistime;
+
+	DEBUG(10, ("SPR_ListEntries called: %d\n", (int)startindex));
+
+	bulkentries->prentries_val =3D NULL;
+	bulkentries->prentries_len =3D 0;
+	*nextstartindex =3D -1;
+
+	if (flags & PRUSERS) {
+		if (startindex =3D=3D 0)
+			collect_users();
+		list =3D &userlist;
+	} else if (flags & PRGROUPS) {
+		if (startindex =3D=3D 0)
+			collect_groups();
+		list =3D &grouplist;
+	} else {
+		DEBUG(0, ("Listing neither users nor groups -- aborting\n"));
+		return PRPERM;
+	}
+
+	bulkentries->prentries_val =3D malloc(MAXENTRIES *
+					    sizeof(struct prlistentries));
+
+	if (bulkentries->prentries_val =3D=3D NULL)
+		return PRNOMEM;
+
+	entries_thistime =3D list->prentries_len - startindex;
+
+	if (entries_thistime > MAXENTRIES)
+		entries_thistime =3D MAXENTRIES;
+
+	memcpy(bulkentries->prentries_val, &(list->prentries_val[startindex]),
+	       entries_thistime * sizeof(struct prlistentries));
+	bulkentries->prentries_len =3D entries_thistime;
+
+	if (startindex + entries_thistime < list->prentries_len) {
+		*nextstartindex =3D startindex + entries_thistime;
+	} else {
+		/* We're finished, clean up list */
+		list->prentries_val =3D NULL;
+		list->prentries_len =3D 0;
+	}
+
+	return PRSUCCESS;
+}
+
+static void usage()
+{
+	fprintf(stderr, "Usage: ptproxy [-?] [-d level] [-s space-replacement]"
+		" DOMAIN-SID\n");
+}
+
+int PR_ExecuteRequest(struct rx_call *z_call);
+void rx_StartServer(int donateme);
+
+static struct afsconf_dir *prdir;
+
+static struct option longopts[] =3D {
+	{ "anyuser", 1, NULL, ANYUSERID },
+	{ "authuser", 1, NULL, AUTHUSERID },
+	{ "administrators", 1, NULL, SYSADMINID },
+	{ NULL, 0, NULL, 0 }
+};
+
+int main(int argc, char **argv)
+{
+	int udpPort =3D 7002;
+	int code;
+
+	int c;
+	extern int optind;
+	extern char *optarg;
+
+	struct rx_securityClass *sc[3];
+	struct rx_service *service;
+
+	DEBUGLEVEL=3D0;
+
+	while ((c =3D getopt_long(argc, argv, "?hd:s:", longopts, NULL)) !=3D -1)=
 {
+		switch(c) {
+		case '?':
+		case 'h':
+			usage();
+			exit(0);
+		case 'd':
+			DEBUGLEVEL =3D atoi(optarg);
+			break;
+		case 's':
+			SPACE_REPLACEMENT =3D optarg[0];
+			break;
+		case SYSADMINID:
+			administrators_sid =3D optarg;
+			break;
+		case ANYUSERID:
+			anyuser_sid =3D optarg;
+			break;
+		case AUTHUSERID:
+			authuser_sid =3D optarg;
+			break;
+		}
+	}
+
+	argc -=3D optind;
+	argv +=3D optind;
+
+	if (argc !=3D 1) {
+		usage();
+		exit(1);
+	}
+
+	domain_sid =3D argv[0];
+
+	if ((administrators_sid =3D=3D NULL) &&
+	    (asprintf(&administrators_sid, "%s-%d",
+		      domain_sid, DOMADM_RID) < 0)) {
+		fprintf(stderr, "Could not alloc administrators_sid\n");
+		exit(1);
+	}
+
+	if ((anyuser_sid =3D=3D NULL) &&
+	    (asprintf(&anyuser_sid, "S-1-5-7") < 0)) {
+		fprintf(stderr, "Could not alloc anyuser_sid\n");
+		exit(1);
+	}
+
+	if ((authuser_sid =3D=3D NULL) &&
+	    ((authuser_sid =3D strdup("S-1-5-11")) =3D=3D NULL)) {
+		fprintf(stderr, "Could not alloc authuser_sid\n");
+		exit(1);
+	}
+
+	if (nss_open(&state, "/lib/libnss_winbind.so") !=3D 0) {
+		fprintf(stderr, "Could not open libnss_winbind.so\n");
+		exit(1);
+	}
+
+	code =3D rx_Init(htons(udpPort));
+
+	if (code) {
+		fprintf(stderr, "rx_Init returned %d\n", code);
+		exit(1);
+	}
+
+	prdir =3D afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
+	if (prdir =3D=3D NULL) {
+		fprintf (stderr, "ptproxy: can't open configuration "
+			 "directory.\n");
+		exit(1);
+	}
+
+	sc[0] =3D rxnull_NewServerSecurityObject();
+
+	if (sc[0] =3D=3D NULL) {
+		fprintf(stderr,
+		       "rxnull_NewServerSecurityObject returned NULL\n");
+		exit(1);
+	}
+
+	sc[1] =3D NULL;
+	sc[2] =3D rxkad_NewServerSecurityObject(0, prdir, afsconf_GetKey,
+					      NULL);
+
+	if (sc[2] =3D=3D NULL) {
+		fprintf(stderr,
+		       "rxkad_NewServerSecurityObject returned NULL\n");
+		exit(1);
+	}
+
+	service =3D rx_NewService(0, 73, "Protection Server", sc, 3,
+				PR_ExecuteRequest);
+
+	if (service =3D=3D NULL) {
+		fprintf(stderr, "rx_NewService returned NULL\n");
+		exit(1);
+	}
+
+	openlog("ptproxy", 0, LOG_DAEMON);
+
+	DEBUG(0, ("Starting ptproxy\n"));
+
+	rx_StartServer(1);
+
+	DEBUG(0, ("success\n"));
+	closelog();
+
+	return 0;
+}

--7AUc2qLy4jB3hD7Z--

--xgyAXRrhYN0wYx8y
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2-rc1-SuSE (GNU/Linux)

iD8DBQFBLfPSduqO64/tJS8RAs/SAJ966Cm0iwQm/i84aZR9+SUTCa1ZnACfcOLz
bAmLFXCii1c3lCc8V2kmXcg=
=4pSE
-----END PGP SIGNATURE-----

--xgyAXRrhYN0wYx8y--