aboutsummaryrefslogtreecommitdiffstats
path: root/USER
diff options
context:
space:
mode:
Diffstat (limited to 'USER')
-rw-r--r--USER/Changes6
-rw-r--r--USER/Makefile.PL18
-rw-r--r--USER/README38
-rw-r--r--USER/USER.pm71
-rw-r--r--USER/USER.xs1385
-rw-r--r--USER/ppport.h540
-rw-r--r--USER/typemap5
7 files changed, 2063 insertions, 0 deletions
diff --git a/USER/Changes b/USER/Changes
new file mode 100644
index 0000000..ff2945b
--- /dev/null
+++ b/USER/Changes
@@ -0,0 +1,6 @@
+Revision history for Perl extension userdrake.
+
+0.01 Fri Feb 28 15:36:17 2003
+ - original version; created by h2xs 1.22 with options
+ -A -n userdrake
+
diff --git a/USER/Makefile.PL b/USER/Makefile.PL
new file mode 100644
index 0000000..0867054
--- /dev/null
+++ b/USER/Makefile.PL
@@ -0,0 +1,18 @@
+use ExtUtils::MakeMaker;
+$Verbose=1;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+my $libs = "" . `pkg-config --libs libuser`;
+chomp $libs;
+$libs .= "-lpam_misc -lpam ";
+WriteMakefile(
+ 'NAME' => 'USER',
+ 'OPTIMIZE' => '-Wno-declaration-after-statement',
+ 'VERSION_FROM' => 'USER.pm',
+ 'OBJECT' => 'USER.o', # link all the C files too
+ 'LIBS' => "$libs", # e.g., '-lm'
+ 'DEFINE' => '-DPACKAGE_NAME=\"userdrake\"', # e.g., '-DHAVE_SOMETHING'
+ 'INC' => "`pkg-config --cflags libuser`", # e.g., '-I. -I/usr/include/other'
+ 'XSPROTOARG' => '-noprototypes',
+ 'TYPEMAPS' => ['../perlobject.map' ],
+);
diff --git a/USER/README b/USER/README
new file mode 100644
index 0000000..91befca
--- /dev/null
+++ b/USER/README
@@ -0,0 +1,38 @@
+userdrake version 0.01
+======================
+
+The README is used to introduce the module and provide instructions on
+how to install the module, any machine dependencies it may have (for
+example C compilers and installed libraries) and any other information
+that should be provided before the module is installed.
+
+A README file is required for CPAN modules since CPAN extracts the
+README file from a module distribution so that people browsing the
+archive can use it get an idea of the modules uses. It is usually a
+good idea to provide version information here so that people can
+decide whether fixes for the module are worth downloading.
+
+INSTALLATION
+
+To install this module type the following:
+
+ perl Makefile.PL
+ make
+ make test
+ make install
+
+DEPENDENCIES
+
+This module requires these other modules and libraries:
+
+ blah blah blah
+
+COPYRIGHT AND LICENCE
+
+Put the correct copyright and licence information here.
+
+Copyright (C) 2003 daouda
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
diff --git a/USER/USER.pm b/USER/USER.pm
new file mode 100644
index 0000000..e95096d
--- /dev/null
+++ b/USER/USER.pm
@@ -0,0 +1,71 @@
+package USER;
+
+use strict;
+require DynaLoader;
+
+our @ISA = qw(DynaLoader);
+our $VERSION = '0.92';
+
+USER->bootstrap($VERSION);
+
+# Preloaded methods go here.
+
+package USER::ADMIN;
+our @ISA = qw();
+
+package USER::ENT;
+our @ISA = qw();
+
+1;
+__END__
+# Below is stub documentation for your module. You'd better edit it!
+
+=head1 NAME
+
+USER - Perl extension for libuser API
+
+=head1 SYNOPSIS
+
+ use USER;
+
+=head1 ABSTRACT
+
+ A user and group account administration library
+
+=head1 DESCRIPTION
+
+ The libuser library implements a standardized interface for manipulating
+ and administering user and group accounts. The library uses pluggable
+ back-ends to interface to its data sources.
+ This is the perl Extension for libuser. It is mostly used by userdrake
+ which is a GUI for user and groups administration
+
+=head2 EXPORT
+
+None by default.
+
+
+
+=head1 SEE ALSO
+
+Mention other useful documentation such as the documentation of
+related modules or operating system documentation (such as man pages
+in UNIX), or any relevant external documentation such as RFCs or
+standards.
+
+If you have a mailing list set up for your module, mention it here.
+
+If you have a web site set up for your module, mention it here.
+
+=head1 AUTHOR
+
+Daouda LO, E<lt>daouda@mandrakesoft.comE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2003 by Mandrakesoft SA
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
diff --git a/USER/USER.xs b/USER/USER.xs
new file mode 100644
index 0000000..ef6f1fb
--- /dev/null
+++ b/USER/USER.xs
@@ -0,0 +1,1385 @@
+/* Copyright (C) 2003-2005 Mandriva SA Daouda Lo (daouda)
+ * This program is free software; you can redistribute it and/or
+ * modify it under the same terms as Perl itself.
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include "ppport.h"
+
+#include <grp.h>
+#include <pwd.h>
+#include <crypt.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <limits.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <glib.h>
+#include <utime.h>
+#include <libuser/user.h>
+#include <libuser/user_private.h>
+
+
+
+#define INVALID (-0x80000000)
+#ifndef _
+#define _(String) gettext(String)
+#endif
+#ifndef N_
+#define N_(String) (String)
+#endif
+
+typedef struct context USER__ADMIN;
+typedef struct lu_ent USER__ENT;
+typedef struct lu_error USER__ERR;
+
+static SV ** convert_value_array_list(register SV **sp, GValueArray *array) {
+ GValue *value;
+ int i;
+ long l;
+ const char *s;
+ for (i = 0; (array != NULL) && (i < array->n_values); i++) {
+ value = g_value_array_get_nth(array, i);
+ /* If the item is a G_TYPE_LONG, add it as a double. */
+ if (G_VALUE_HOLDS_LONG(value)) {
+ l = g_value_get_long(value);
+ XPUSHs(sv_2mortal(newSViv(l)));
+ } else if (G_VALUE_HOLDS_STRING(value)) {
+ s = g_value_get_string(value);
+ XPUSHs(sv_2mortal(newSVpv(s, 0)));
+ }
+ }
+ return sp;
+}
+
+/* Populate a user's home directory, copying data from a named skeleton
+ * directory, setting all ownerships as given, and setting the mode of
+ * the top-level directory as given. */
+int
+lu_homedir_populate(const char *skeleton, const char *directory,
+ uid_t owner, gid_t group, mode_t mode,
+ USER__ERR **error)
+{
+ struct dirent *ent;
+ DIR *dir;
+ struct stat st;
+ char skelpath[PATH_MAX], path[PATH_MAX], buf[PATH_MAX];
+ struct utimbuf timebuf;
+ int ifd = -1, ofd = -1, i;
+ off_t offset;
+ LU_ERROR_CHECK(error);
+ /* If the destination directory exists, return. */
+ dir = opendir(skeleton);
+ if (dir == NULL) {
+ lu_error_new(error, lu_error_generic,
+ _("Error reading `%s': %s"), skeleton,
+ strerror(errno));
+ return 0;
+ }
+ /* Create the top-level directory. */
+ if ((mkdir(directory, mode) == -1) && (errno != EEXIST)) {
+ lu_error_new(error, lu_error_generic,
+ _("Error creating `%s': %s"), directory,
+ strerror(errno));
+ closedir(dir);
+ return 0;
+ }
+ /* Set the ownership on the top-level directory. */
+ chown(directory, owner, group);
+ while ((ent = readdir(dir)) != NULL) {
+ /* Iterate through each item in the directory. */
+ /* Skip over self and parent hard links. */
+ if (strcmp(ent->d_name, ".") == 0) {
+ continue;
+ }
+ if (strcmp(ent->d_name, "..") == 0) {
+ continue;
+ }
+ /* Build the path of the skeleton file or directory and
+ * its corresponding member in the new tree. */
+ snprintf(skelpath, sizeof(skelpath), "%s/%s",
+ skeleton, ent->d_name);
+ snprintf(path, sizeof(path), "%s/%s", directory,
+ ent->d_name);
+ /* What we do next depends on the type of entry we're
+ * looking at. */
+ if (lstat(skelpath, &st) != -1) {
+ /* We always want to preserve atime/mtime. */
+ timebuf.actime = st.st_atime;
+ timebuf.modtime = st.st_mtime;
+ /* If it's a directory, descend into it. */
+ if (S_ISDIR(st.st_mode)) {
+ if (!lu_homedir_populate(skelpath,
+ path,
+ owner,
+ st.st_gid ?: group,
+ st.st_mode,
+ error)) {
+ /* Aargh! Fail up. */
+ closedir(dir);
+ return 0;
+ }
+ /* Set the date on the directory. */
+ utime(path, &timebuf);
+ continue;
+ }
+ /* If it's a symlink, duplicate it. */
+ if (S_ISLNK(st.st_mode)) {
+ if (readlink(skelpath, buf,
+ sizeof(buf) - 1) != -1) {
+ buf[sizeof(buf) - 1] = '\0';
+ symlink(buf, path);
+ lchown(path, owner, st.st_gid ?: group);
+ utime(path, &timebuf);
+ }
+ continue;
+ }
+ /* If it's a regular file, copy it. */
+ if (S_ISREG(st.st_mode)) {
+ /* Open both the input and output
+ * files. If we fail to do either,
+ * we have to give up. */
+ ifd = open(skelpath, O_RDONLY);
+ if (ifd != -1) {
+ ofd = open(path,
+ O_EXCL | O_CREAT | O_WRONLY,
+ st.st_mode);
+ }
+ if ((ifd == -1) || (ofd == -1)) {
+ /* Sorry, no can do. */
+ close (ifd);
+ close (ofd);
+ continue;
+ }
+ /* Now just copy the data. */
+ do {
+ i = read(ifd, &buf, sizeof(buf));
+ if (i > 0) {
+ write(ofd, buf, i);
+ }
+ } while (i > 0);
+ /* Close the files. */
+ offset = lseek(ofd, 0, SEEK_CUR);
+ if (offset != ((off_t) -1)) {
+ ftruncate(ofd, offset);
+ }
+ close (ifd);
+ close (ofd);
+ /* Set the ownership and timestamp on
+ * the new file. */
+ chown(path, owner, st.st_gid ?: group);
+ utime(path, &timebuf);
+ continue;
+ }
+ /* Note that we don't copy device specials. */
+ }
+ }
+ closedir(dir);
+ return 1;
+}
+
+/* Recursively remove a user's home (or really, any) directory. */
+int
+lu_homedir_remove(const char *directory, struct lu_error ** error)
+{
+ struct dirent *ent;
+ DIR *dir;
+ struct stat st;
+ char path[PATH_MAX];
+ LU_ERROR_CHECK(error);
+ /* Open the directory. This catches the case that it's already gone. */
+ dir = opendir(directory);
+ if (dir == NULL) {
+ lu_error_new(error, lu_error_stat,
+ _("Error removing `%s': %s"), directory,
+ strerror(errno));
+ return 0;
+ }
+ /* Iterate over all of its contents. */
+ while ((ent = readdir(dir)) != NULL) {
+ /* Skip over the self and parent hard links. */
+ if (strcmp(ent->d_name, ".") == 0) {
+ continue;
+ }
+ if (strcmp(ent->d_name, "..") == 0) {
+ continue;
+ }
+ /* Generate the full path of the next victim. */
+ snprintf(path, sizeof(path), "%s/%s", directory, ent->d_name);
+ /* What we do next depends on whether or not the next item to
+ * remove is a directory. */
+ if (lstat(path, &st) != -1) {
+ if (S_ISDIR(st.st_mode)) {
+ /* We decend into subdirectories... */
+ if (lu_homedir_remove(path, error) == FALSE) {
+ closedir(dir);
+ return 0;
+ }
+ } else {
+ /* ... and unlink everything else. */
+ if (unlink(path) == -1) {
+ lu_error_new(error,
+ lu_error_generic,
+ _("Error removing "
+ "`%s': %s"),
+ path,
+ strerror
+ (errno));
+ closedir(dir);
+ return 0;
+ }
+ }
+ }
+ }
+ closedir(dir);
+
+ /* As a final step, remove the directory itself. */
+ if (rmdir(directory) == -1) {
+ lu_error_new(error, lu_error_generic,
+ _("Error removing `%s': %s"), directory,
+ strerror(errno));
+ return 0;
+ }
+
+ return 1;
+}
+/* Move a directory from one place to another. */
+int
+lu_homedir_move(const char *oldhome, const char *newhome,
+ USER__ERR ** error)
+{
+ struct stat st;
+ LU_ERROR_CHECK(error);
+ /* If the directory exists... */
+ if (stat(oldhome, &st) != -1) {
+ /* ... and we can copy it ... */
+ if (lu_homedir_populate(oldhome, newhome,
+ st.st_uid, st.st_gid, st.st_mode,
+ error)) {
+ /* ... remove the old one. */
+ return lu_homedir_remove(oldhome, error);
+ }
+ }
+ return 0;
+}
+/* Concatenate a string onto another string on the heap. */
+char *
+lu_strconcat(char *existing, const char *appendee)
+{
+ char *tmp;
+ if (existing == NULL) {
+ existing = g_strdup(appendee);
+ } else {
+ tmp = g_strconcat(existing, appendee, NULL);
+ g_free(existing);
+ existing = tmp;
+ }
+ return existing;
+}
+/* Send nscd an arbitrary signal. */
+void
+lu_signal_nscd(int signum)
+{
+ FILE *fp;
+ char buf[LINE_MAX];
+ /* If it's running, then its PID is in this file. Open it. */
+ if ((fp = fopen("/var/run/nscd.pid", "r")) != NULL) {
+ /* Read the PID. */
+ memset(buf, 0, sizeof(buf));
+ fgets(buf, sizeof(buf), fp);
+ /* If the PID is sane, send it a signal. */
+ if (strlen(buf) > 0) {
+ pid_t pid = atol(buf);
+ if (pid != 0) {
+ kill(pid, signum);
+ }
+ }
+ fclose(fp);
+ }
+}
+
+/* Send nscd a SIGHUP. */
+void
+lu_hup_nscd()
+{
+ lu_signal_nscd(SIGHUP);
+}
+
+/* Create a mail spool for the user. */
+int
+lu_mailspool_create_remove(USER__ADMIN *ctx, USER__ENT *ent,
+ int action)
+{
+ GValueArray *array;
+ GValue *value;
+ const char *spooldir;
+ long uid, gid;
+ char *p, *username;
+ struct group grp, *err;
+ USER__ENT *groupEnt;
+ USER__ERR *error = NULL;
+ char buf[LINE_MAX * 4];
+ int fd;
+
+ /* Find the GID of the owner of the file. */
+ gid = INVALID;
+ groupEnt = lu_ent_new();
+ if (lu_group_lookup_name(ctx, "mail", groupEnt, &error)) {
+ array = lu_ent_get(groupEnt, LU_GIDNUMBER);
+ if (array != NULL) {
+ value = g_value_array_get_nth(array, 0);
+ if (G_VALUE_HOLDS_LONG(value)) {
+ gid = g_value_get_long(value);
+ } else
+ if (G_VALUE_HOLDS_STRING(value)) {
+ gid = strtol(g_value_get_string(value), &p, 0);
+ if (*p != '\0') {
+ gid = INVALID;
+ }
+ } else {
+ g_assert_not_reached();
+ }
+ }
+ }
+ lu_ent_free(groupEnt);
+
+ /* Er, okay. Check with libc. */
+ if (gid == INVALID) {
+ if ((getgrnam_r("mail", &grp, buf, sizeof(buf), &err) == 0) &&
+ (err == &grp)) {
+ gid = grp.gr_gid;
+ }
+ }
+
+ /* Aiieee. Use the user's group. */
+ if (gid == INVALID) {
+ array = lu_ent_get(ent, LU_GIDNUMBER);
+ if (array != NULL) {
+ value = g_value_array_get_nth(array, 0);
+ if (G_VALUE_HOLDS_LONG(value)) {
+ gid = g_value_get_long(value);
+ } else
+ if (G_VALUE_HOLDS_STRING(value)) {
+ gid = strtol(g_value_get_string(value), &p, 0);
+ if (*p == '\0') {
+ gid = INVALID;
+ }
+ } else {
+ g_warning("Unable to determine user's GID.");
+ g_assert_not_reached();
+ }
+ }
+ }
+ g_return_val_if_fail(gid != INVALID, FALSE);
+
+ /* Now get the user's UID. */
+ array = lu_ent_get(ent, LU_UIDNUMBER);
+ if (array != NULL) {
+ value = g_value_array_get_nth(array, 0);
+ uid = INVALID;
+ if (G_VALUE_HOLDS_LONG(value)) {
+ uid = g_value_get_long(value);
+ } else
+ if (G_VALUE_HOLDS_STRING(value)) {
+ uid = strtol(g_value_get_string(value), &p, 0);
+ if (*p != '\0') {
+ uid = INVALID;
+ }
+ } else {
+ g_warning("Unable to determine user's UID.");
+ g_assert_not_reached();
+ }
+ }
+ g_return_val_if_fail(uid != INVALID, FALSE);
+
+ /* Now get the user's login. */
+ username = NULL;
+ array = lu_ent_get(ent, LU_USERNAME);
+ if (array != NULL) {
+ value = g_value_array_get_nth(array, 0);
+ if (G_VALUE_HOLDS_LONG(value)) {
+ username = g_strdup_printf("%ld",
+ g_value_get_long(value));
+ } else
+ if (G_VALUE_HOLDS_STRING(value)) {
+ username = g_value_dup_string(value);
+ } else {
+ g_warning("Unable to determine user's name.");
+ g_assert_not_reached();
+ }
+ }
+ g_return_val_if_fail(username != NULL, FALSE);
+
+ /* Get the location of the spool directory. */
+ spooldir = lu_cfg_read_single(ctx, "defaults/mailspooldir",
+ "/var/mail");
+
+ /* That wasn't that hard. Now we just need to create the file. */
+ p = g_strdup_printf("%s/%s", spooldir, username);
+ g_free(username);
+ if (action) {
+ fd = open(p, O_WRONLY | O_CREAT, 0);
+ if (fd != -1) {
+ fchown(fd, uid, gid);
+ fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+ close(fd);
+ g_free(p);
+ return 1;
+ }
+ } else {
+ if (unlink(p) == 0) {
+ g_free(p);
+ return 1;
+ }
+ if (errno == ENOENT) {
+ g_free(p);
+ return 1;
+ }
+ }
+ g_free(p);
+
+ return 0;
+}
+
+MODULE = USER PACKAGE = USER::ADMIN PREFIX = Admin_
+
+USER::ADMIN *
+Admin_new(CLASS)
+ char *CLASS
+ CODE:
+ USER__ERR *error = NULL;
+ RETVAL = (USER__ADMIN *)lu_start(NULL, 0, NULL, NULL, lu_prompt_console_quiet, NULL, &error);
+ if( RETVAL == NULL ){
+ warn("unable to malloc USER__ADMIN");
+ XSRETURN_UNDEF;
+ }
+ OUTPUT:
+ RETVAL
+
+void
+Admin_DESTROY(self)
+ USER::ADMIN *self
+ CODE:
+ if (self) lu_end(self);
+
+int
+Admin_UserAdd(self, ent, is_system, dont_create_home)
+ USER::ADMIN *self
+ USER::ENT *ent
+ int is_system
+ int dont_create_home
+ CODE:
+ USER__ERR *error = NULL;
+ long uidNumber, gidNumber;
+ char *skeleton = "/etc/skel", *homeDirectory = NULL;
+ GValueArray *values;
+ GValue *value;
+ /* GMOT (Great Moment Of Truth) */
+ if (lu_user_add(self, ent, &error) == FALSE) {
+ croak(_("Account creation failed: '%s'.\n"), error ? error->string : "Unknown error");
+ RETVAL = 0;
+ } else RETVAL = 1 ;
+ if (!dont_create_home) {
+ /* Read the user's UID. */
+ values = lu_ent_get(ent, LU_UIDNUMBER);
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_LONG(value)) {
+ uidNumber = g_value_get_long(value);
+ } else
+ if (G_VALUE_HOLDS_STRING(value)) {
+ uidNumber = atol(g_value_get_string(value));
+ } else {
+ warn(_("Cannot get Uid number"));
+ }
+
+ /* Read the user's GID. */
+ values = lu_ent_get(ent, LU_GIDNUMBER);
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_LONG(value)) {
+ gidNumber = g_value_get_long(value);
+ } else
+ if (G_VALUE_HOLDS_STRING(value)) {
+ gidNumber = atol(g_value_get_string(value));
+ } else {
+ warn(_("Cannot retrieve value"));
+ }
+
+ /* Read the user's home directory. */
+ values = lu_ent_get(ent, LU_HOMEDIRECTORY);
+ value = g_value_array_get_nth(values, 0);
+ homeDirectory = g_value_get_string(value);
+
+ if (lu_homedir_populate(skeleton, homeDirectory,
+ uidNumber, gidNumber, 0700,
+ &error) == 0) {
+ warn(_("Error creating `%s': %s"), homeDirectory, error ? error->string : "unknown error");
+ RETVAL = 2;
+ }
+
+ /* Create a mail spool for the user. */
+ if (lu_mailspool_create_remove(self, ent, 1) != 1) {
+ warn(_("Error creating mail spool.\n"));
+ RETVAL = 3;
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+int
+Admin_IsLocked(self, ent)
+ USER::ADMIN *self
+ USER::ENT *ent
+ CODE:
+ USER__ERR *error = NULL;
+ if (lu_user_islocked(self, ent, &error)) {
+ RETVAL = 1;
+ } else { RETVAL = 0; };
+ OUTPUT:
+ RETVAL
+
+int
+Admin_Lock(self, ent)
+ USER::ADMIN *self
+ USER::ENT *ent
+ CODE:
+ USER__ERR *error = NULL;
+ if (lu_user_lock(self, ent, &error) == FALSE) {
+ RETVAL = 0;
+ } else { RETVAL = 1; };
+ OUTPUT:
+ RETVAL
+
+int
+Admin_UnLock(self, ent)
+ USER::ADMIN *self
+ USER::ENT *ent
+ CODE:
+ USER__ERR *error = NULL;
+ if (lu_user_unlock(self, ent, &error) == FALSE) {
+ RETVAL = 0;
+ } else { RETVAL = 1; };
+ OUTPUT:
+ RETVAL
+
+void
+Admin_UserModify(self, ent)
+ USER::ADMIN *self
+ USER::ENT *ent
+ PPCODE:
+ USER__ERR *error = NULL;
+ if (lu_user_modify(self, ent, &error) == FALSE) {
+ croak(_("User could not be modified: '%s'.\n"), error ? error->string : "Unknown error");
+ }
+
+int
+Admin_UserDel(self, ent)
+ USER::ADMIN *self
+ USER::ENT *ent
+ CODE:
+ USER__ERR *error = NULL;
+ if (lu_user_delete(self, ent, &error) == FALSE) {
+ croak(_("User Could Not be deleted: '%s'.\n"), error ? error->string : "Unknown error");
+ RETVAL = 0;
+ } else RETVAL = 1 ;
+ OUTPUT:
+ RETVAL
+
+void
+Admin_InitUser(self, name, is_system)
+ USER::ADMIN *self
+ char *name
+ int is_system
+ PPCODE:
+ USER__ENT *ent;
+ ent = lu_ent_new();
+ lu_user_default(self, name, is_system, ent);
+ XPUSHs(sv_2mortal(sv_bless(newRV_noinc(newSViv(ent)), gv_stashpv("USER::ENT", 1))));
+
+void
+Admin_UserSetPass(self, ent, userPasswd)
+ USER::ADMIN *self
+ USER::ENT *ent
+ char *userPasswd
+ PPCODE:
+ USER__ERR *error = NULL;
+ gboolean crypted = FALSE;
+ if (lu_user_setpass(self, ent, userPasswd, crypted, &error) == FALSE) {
+ croak(_("Failed to set password: '%s'.\n"), error ? error->string : _("unknown error"));
+ if (error) { lu_error_free(&error); }
+ }
+
+void
+Admin_LookupUserByName(self, name)
+ USER::ADMIN *self
+ char *name
+ PPCODE:
+ USER__ENT *ent;
+ USER__ERR *error = NULL;
+ ent = lu_ent_new();
+ if (lu_user_lookup_name(self, name, ent, &error)) {
+ XPUSHs(sv_2mortal(sv_bless(newRV_noinc(newSViv(ent)), gv_stashpv("USER::ENT", 1))));
+ } else {
+ lu_ent_free(ent);
+ }
+
+void
+Admin_LookupUserById(self, id)
+ USER::ADMIN *self
+ long id
+ PPCODE:
+ USER__ENT *ent;
+ USER__ERR *error = NULL;
+ ent = lu_ent_new();
+ if (lu_user_lookup_id(self, id, ent, &error)) {
+ XPUSHs(sv_2mortal(sv_bless(newRV_noinc(newSViv(ent)), gv_stashpv("USER::ENT", 1))));
+ } else {
+ lu_ent_free(ent);
+ }
+
+void
+Admin_LookupGroupByName(self, name)
+ USER::ADMIN *self
+ char *name
+ PPCODE:
+ USER__ENT *ent;
+ USER__ERR *error = NULL;
+ ent = lu_ent_new();
+ if (lu_group_lookup_name(self, name, ent, &error)) {
+ XPUSHs(sv_2mortal(sv_bless(newRV_noinc(newSViv(ent)), gv_stashpv("USER::ENT", 1))));
+ } else {
+ lu_ent_free(ent);
+ }
+
+void
+Admin_LookupGroupById(self, id)
+ USER::ADMIN *self
+ int id
+ PPCODE:
+ USER__ENT *ent;
+ USER__ERR *error = NULL;
+ ent = lu_ent_new();
+ if (lu_group_lookup_id(self, id, ent, &error)) {
+ XPUSHs(sv_2mortal(sv_bless(newRV_noinc(newSViv(ent)), gv_stashpv("USER::ENT", 1))));
+ } else {
+ lu_ent_free(ent);
+ }
+
+void
+Admin_GroupAdd(self, ent)
+ USER::ADMIN *self
+ USER::ENT *ent
+ PPCODE:
+ USER__ERR *error = NULL;
+ if (lu_group_add(self, ent, &error) == FALSE) {
+ warn(_("Group creation failed.\n"));
+ }
+
+void
+Admin_GroupModify(self, ent)
+ USER::ADMIN *self
+ USER::ENT *ent
+ PPCODE:
+ USER__ERR *error = NULL;
+ if (lu_group_modify(self, ent, &error) == FALSE) {
+ croak(_("Group could not be modified: '%s'.\n"), error ? error->string : "Unknown error");
+ }
+
+int
+Admin_GroupDel(self, ent)
+ USER::ADMIN *self
+ USER::ENT *ent
+ CODE:
+ USER__ERR *error = NULL;
+ if (lu_group_delete(self, ent, &error) == FALSE) {
+ croak(_("Group could not be deleted: '%s'.\n"), error ? error->string : "Unknown error");
+ RETVAL = 0;
+ } else RETVAL = 1 ;
+ OUTPUT:
+ RETVAL
+
+void
+Admin_InitGroup(self, name, is_system)
+ USER::ADMIN *self
+ char *name
+ int is_system
+ PPCODE:
+ USER__ENT *ent;
+ ent = lu_ent_new();
+ lu_group_default(self, name, is_system, ent);
+ XPUSHs(sv_2mortal(sv_bless(newRV_noinc(newSViv(ent)), gv_stashpv("USER::ENT", 1))));
+
+AV *
+Admin_EnumerateUsersByGroup(self, name)
+ USER::ADMIN *self
+ char *name
+ CODE:
+ int c;
+ USER__ERR *error = NULL;
+ RETVAL = (AV*)sv_2mortal((SV*)newAV());
+ GValueArray *results;
+ results = lu_users_enumerate_by_group(self, name, &error);
+ for (c = 0; (results != NULL) && (c < results->n_values); c++) {
+ if( av_store(RETVAL, c, newSVpv(g_value_get_string(g_value_array_get_nth(results, c)), 0)) == NULL ){
+ warn("XS_UsersEnumerateFull: failed to store elems");
+ }
+ }
+ g_value_array_free(results);
+ OUTPUT:
+ RETVAL
+
+AV *
+Admin_EnumerateGroupsByUser(self, name)
+ USER::ADMIN *self
+ char *name
+ CODE:
+ int c;
+ USER__ERR *error = NULL;
+ RETVAL = (AV*)sv_2mortal((SV*)newAV());
+ GValueArray *results;
+ results = lu_groups_enumerate_by_user(self, name, &error);
+ for (c = 0; (results != NULL) && (c < results->n_values); c++) {
+ if( av_store(RETVAL, c, newSVpv(g_value_get_string(g_value_array_get_nth(results, c)), 0)) == NULL ){
+ warn("XS_UsersEnumerateFull: failed to store elems");
+ }
+ }
+ g_value_array_free(results);
+ OUTPUT:
+ RETVAL
+
+AV *
+Admin_UsersEnumerate(self)
+ USER::ADMIN *self
+ CODE:
+ int c;
+ USER__ERR *error = NULL;
+ const char *pattern = NULL;
+ RETVAL = (AV*)sv_2mortal((SV*)newAV());
+ GValueArray *users;
+ users = lu_users_enumerate(self, pattern, &error);
+ for (c = 0; ( users != NULL) && (c < users->n_values); c++) {
+ if( av_store(RETVAL, c, newSVpv(g_value_get_string(g_value_array_get_nth(users, c)), 0)) == NULL ){
+ warn("XS_UserEnumerate: failed to store elements of array");
+ }
+ }
+ g_value_array_free(users);
+ OUTPUT:
+ RETVAL
+
+AV *
+Admin_GroupsEnumerate(self)
+ USER::ADMIN *self
+ CODE:
+ int c;
+ USER__ERR *error = NULL;
+ const char *pattern = NULL;
+ RETVAL = (AV*)sv_2mortal((SV*)newAV());
+ GValueArray *groups;
+ groups = lu_groups_enumerate(self, pattern, &error);
+ for (c = 0; (groups != NULL) && (c < groups->n_values); c++) {
+ if( av_store(RETVAL, c, newSVpv(g_value_get_string(g_value_array_get_nth(groups, c)), 0)) == NULL ){
+ warn("XS_GroupEnumerate: failed to store elements of array");
+ }
+ }
+ g_value_array_free(groups);
+ OUTPUT:
+ RETVAL
+
+AV *
+Admin_UsersEnumerateFull(self)
+ USER::ADMIN *self
+ CODE:
+ int c;
+ USER__ERR *error = NULL;
+ const char *pattern = NULL;
+ RETVAL = (AV*)sv_2mortal((SV*)newAV());
+ GPtrArray *accounts;
+ accounts = lu_users_enumerate_full(self, pattern, &error);
+ for (c = 0; (accounts != NULL) && (c < accounts->len); c++) {
+ if( av_store(RETVAL, c, sv_bless(newRV_noinc(newSViv(g_ptr_array_index(accounts, c))), gv_stashpv("USER::ENT", 1))) == NULL ){
+ warn("XS_UsersEnumerateFull: failed to store elems");
+ }
+ }
+ g_ptr_array_free(accounts, TRUE);
+ OUTPUT:
+ RETVAL
+
+AV *
+Admin_GroupsEnumerateFull(self)
+ USER::ADMIN *self
+ CODE:
+ int c;
+ USER__ERR *error = NULL;
+ const char *pattern = NULL;
+ RETVAL = (AV*)sv_2mortal((SV*)newAV());
+ GPtrArray *accounts;
+ accounts = lu_groups_enumerate_full(self, pattern, &error);
+ for (c = 0; (accounts != NULL) && (c < accounts->len); c++) {
+ if( av_store(RETVAL, c, sv_bless(newRV_noinc(newSViv(g_ptr_array_index(accounts, c))), gv_stashpv("USER::ENT", 1))) == NULL ){
+ warn("XS_UsersEnumerateFull: failed to store elems");
+ }
+ }
+ g_ptr_array_free(accounts, TRUE);
+ OUTPUT:
+ RETVAL
+
+AV *
+Admin_GetUserShells(self)
+ USER::ADMIN *self
+ CODE:
+ int i = 0;
+ const char *shell;
+ RETVAL = (AV*)sv_2mortal((SV*)newAV());
+ setusershell();
+ while ((shell = getusershell()) != NULL) {
+ av_store(RETVAL, i, newSVpv(shell, 0));
+ i++;
+ }
+ endusershell();
+ OUTPUT:
+ RETVAL
+
+void
+Admin_CleanHome(self, ent)
+ USER::ADMIN *self
+ USER::ENT *ent
+ PPCODE:
+ USER__ERR *error = NULL;
+ GValueArray *values;
+ GValue *value;
+ const char *tmp = NULL;
+ values = lu_ent_get(ent, LU_HOMEDIRECTORY);
+ if ((values == NULL) || (values->n_values == 0)) {
+ warn(_("No home directory for the user.\n"));
+ } else {
+ value = g_value_array_get_nth(values, 0);
+ tmp = g_value_get_string(value);
+ if (lu_homedir_remove(tmp, &error) == FALSE) {
+ if (error->code == lu_error_stat)
+ warn(_("Home Directory Could Not be deleted: '%s'.\n"), error ? error->string : "Unknown error");
+ else
+ croak(_("Home Directory Could Not be deleted: '%s'.\n"), error ? error->string : "Unknown error");
+ }
+ }
+
+void
+Admin_CleanSpool(self, ent)
+ USER::ADMIN *self
+ USER::ENT *ent
+ PPCODE:
+ if (lu_mailspool_create_remove(self, ent, 0) != 1) {
+ warn(_("Error deleting mail spool.\n"));
+ }
+
+MODULE = USER PACKAGE = USER::ENT PREFIX = Ent_
+
+USER::ENT *
+Ent_new (CLASS)
+ char *CLASS
+ CODE:
+ RETVAL = (USER__ENT *)lu_ent_new();
+ if( RETVAL == NULL ){
+ warn("unable to malloc USER__ENT");
+ XSRETURN_UNDEF;
+ }
+ OUTPUT:
+ RETVAL
+
+void
+Ent_DESTROY(self)
+ USER::ENT *self
+ CODE:
+ if (self) lu_ent_free(self);
+
+void
+Ent_EntType(self)
+ USER::ENT *self
+ PPCODE:
+ switch (self->type) {
+ case lu_invalid:
+ break;
+ case lu_user:
+ XPUSHs(sv_2mortal(newSVpv("user", 0)));
+ break;
+ case lu_group:
+ XPUSHs(sv_2mortal(newSVpv("group", 0)));
+ break;
+ default:
+ break;
+ }
+
+void
+Ent_UserName(self, ssv)
+ USER::ENT *self
+ SV * ssv
+ PPCODE:
+ GValueArray *values;
+ GValue *value, val;
+ if ( SvIOK(ssv) && SvIV(ssv) == -65533) {
+ values = lu_ent_get(self, LU_USERNAME);
+ if (values != NULL) {
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_STRING(value)) {
+ XPUSHs(sv_2mortal(newSVpv(g_value_get_string(value), 0)));
+ } else if (G_VALUE_HOLDS_LONG(value)) {
+ XPUSHs(sv_2mortal(newSVpv(g_strdup_printf("%ld", g_value_get_long(value)), 0)));
+ }
+ }
+ } else if( SvPOK( ssv ) ) {
+ memset(&val, 0, sizeof(val));
+ g_value_init(&val, G_TYPE_STRING);
+ g_value_set_string(&val, SvPV(ssv,PL_na));
+ lu_ent_clear(self, LU_USERNAME);
+ lu_ent_add(self, LU_USERNAME, &val);
+ } else {
+ warn("XS_UserName: Cannot make operation on LU_USERNAME attribute");
+ }
+
+void
+Ent_GroupName(self, ssv)
+ USER::ENT *self
+ SV * ssv
+ PPCODE:
+ GValueArray *values;
+ GValue *value, val;
+ if ( SvIOK(ssv) && SvIV(ssv) == -65533) {
+ values = lu_ent_get(self, LU_GROUPNAME);
+ if (values != NULL) {
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_STRING(value)) {
+ XPUSHs(sv_2mortal(newSVpv(g_value_get_string(value), 0)));
+ } else if (G_VALUE_HOLDS_LONG(value)) {
+ XPUSHs(sv_2mortal(newSVpv(g_strdup_printf("%ld", g_value_get_long(value)), 0)));
+ }
+ }
+ } else if( SvPOK( ssv ) ) {
+ memset(&val, 0, sizeof(val));
+ g_value_init(&val, G_TYPE_STRING);
+ g_value_set_string(&val, SvPV(ssv,PL_na));
+ lu_ent_clear(self, LU_GROUPNAME);
+ lu_ent_add(self, LU_GROUPNAME, &val);
+ } else {
+ warn("XS_GroupName: Cannot make operation on LU_GROUPNAME attribute");
+ }
+
+AV*
+Ent_MemberName(self, rv, AddOrDel)
+ USER::ENT *self
+ SV *rv
+ int AddOrDel
+ CODE:
+ GValueArray *members;
+ GValue *value, val;
+ RETVAL = (AV*)sv_2mortal((SV*)newAV());
+ char *member = NULL;
+ int c;
+ if ( SvIOK(rv) && SvIV(rv) == 1) {
+ members = lu_ent_get(self, LU_MEMBERNAME);
+ for (c = 0; (members != NULL) && (c < members->n_values); c++) {
+ if( av_store(RETVAL, c, newSVpv(g_value_get_string(g_value_array_get_nth(members, c)), 0)) == NULL ){
+ warn("XS_MemberName: failed to store elements of array");
+ }
+ }
+ } else if ( SvPOK( rv ) ) {
+ memset(&val, 0, sizeof(val));
+ g_value_init(&val, G_TYPE_STRING);
+ member = SvPV(rv, PL_na);
+ g_value_set_string(&val, member);
+ if (AddOrDel == 1) {
+ lu_ent_add(self, LU_MEMBERNAME, &val);
+ } else if (AddOrDel == 2) {
+ lu_ent_del(self, LU_MEMBERNAME, &val);
+ }
+ g_value_reset(&val);
+ } else {
+ croak("XS_MemberName: Cannot make operation on LU_MEMBERNAME attribute");
+ };
+ OUTPUT:
+ RETVAL
+
+void
+Ent_Uid(self, ssv)
+ USER::ENT *self
+ SV *ssv;
+ PPCODE:
+ GValueArray *values;
+ GValue *value, val;
+ if ( SvIOK(ssv) ) {
+ if (SvIV(ssv) == -65533) {
+ values = lu_ent_get(self, LU_UIDNUMBER);
+ if (values != NULL) {
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_LONG(value)) {
+ XPUSHs(sv_2mortal(newSViv(g_value_get_long(value))));
+ } else if (G_VALUE_HOLDS_STRING(value)) {
+ XPUSHs(sv_2mortal(newSViv(atol(g_value_get_string(value)))));
+ }
+ }
+ } else {
+ memset(&val, 0, sizeof(val));
+ g_value_init(&val, G_TYPE_LONG);
+ g_value_set_long(&val, (long)SvIV( ssv ));
+ lu_ent_clear(self, LU_UIDNUMBER);
+ lu_ent_add(self, LU_UIDNUMBER, &val);
+ }
+ } else {
+ warn("XS_Uid: Cannot make operation on LU_UIDNUMBER attribute");
+ }
+
+void
+Ent_Gid(self, ssv)
+ USER::ENT *self
+ SV *ssv;
+ PPCODE:
+ GValueArray *values;
+ GValue *value, val;
+ if ( SvIOK(ssv) ) {
+ if (SvIV(ssv) == -65533) {
+ values = lu_ent_get(self, LU_GIDNUMBER);
+ if (values != NULL) {
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_LONG(value)) {
+ XPUSHs(sv_2mortal(newSViv(g_value_get_long(value))));
+ } else if (G_VALUE_HOLDS_STRING(value)) {
+ XPUSHs(sv_2mortal(newSViv(atol(g_value_get_string(value)))));
+ }
+ }
+ } else {
+ memset(&val, 0, sizeof(val));
+ g_value_init(&val, G_TYPE_LONG);
+ g_value_set_long(&val, (long)SvIV( ssv ));
+ lu_ent_clear(self, LU_GIDNUMBER);
+ lu_ent_add(self, LU_GIDNUMBER, &val);
+ }
+ } else {
+ warn("XS_Gid: Cannot make operation on LU_GIDNUMBER attribute");
+ }
+
+void
+Ent_Gecos(self, ssv)
+ USER::ENT *self
+ SV *ssv;
+ PPCODE:
+ GValueArray *values;
+ GValue *value, val;
+ if ( SvIOK(ssv) && SvIV(ssv) == -65533) {
+ values = lu_ent_get(self, LU_GECOS);
+ if (values != NULL) {
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_STRING(value)) {
+ XPUSHs(sv_2mortal(newSVpv(g_value_get_string(value), 0)));
+ } else if (G_VALUE_HOLDS_LONG(value)) {
+ XPUSHs(sv_2mortal(newSVpv(g_strdup_printf("%ld", g_value_get_long(value)), 0)));
+ }
+ }
+ } else if( SvPOK( ssv ) ) {
+ memset(&val, 0, sizeof(val));
+ g_value_init(&val, G_TYPE_STRING);
+ g_value_set_string(&val, SvGChar(ssv));
+ lu_ent_clear(self, LU_GECOS);
+ lu_ent_add(self, LU_GECOS, &val);
+ } else {
+ warn("XS_Gecos: Cannot make operation on LU_GECOS attribute");
+ }
+
+void
+Ent_HomeDir(self, ssv)
+ USER::ENT *self
+ SV *ssv
+ PPCODE:
+ GValueArray *values;
+ GValue *value, val;
+ if ( SvIOK(ssv) && SvIV(ssv) == -65533) {
+ values = lu_ent_get(self, LU_HOMEDIRECTORY);
+ if (values != NULL) {
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_STRING(value)) {
+ XPUSHs(sv_2mortal(newSVpv(g_value_get_string(value), 0)));
+ } else if (G_VALUE_HOLDS_LONG(value)) {
+ XPUSHs(sv_2mortal(newSVpv(g_strdup_printf("%ld", g_value_get_long(value)), 0)));
+ }
+ }
+ } else if( SvPOK( ssv ) ) {
+ memset(&val, 0, sizeof(val));
+ g_value_init(&val, G_TYPE_STRING);
+ g_value_set_string(&val, SvPV(ssv,PL_na));
+ lu_ent_clear(self, LU_HOMEDIRECTORY);
+ lu_ent_add(self, LU_HOMEDIRECTORY, &val);
+ } else {
+ warn("XS_HomeDir: Cannot make operation on LU_HOMEDIRECTORY attribute");
+ }
+
+void
+Ent_LoginShell(self, ssv)
+ USER::ENT *self
+ SV *ssv
+ PPCODE:
+ GValueArray *values;
+ GValue *value, val;
+ if ( SvIOK(ssv) && SvIV(ssv) == -65533) {
+ values = lu_ent_get(self, LU_LOGINSHELL);
+ if (values != NULL) {
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_STRING(value)) {
+ XPUSHs(sv_2mortal(newSVpv(g_value_get_string(value), 0)));
+ } else if (G_VALUE_HOLDS_LONG(value)) {
+ XPUSHs(sv_2mortal(newSVpv(g_strdup_printf("%ld", g_value_get_long(value)), 0)));
+ }
+ }
+ } else if( SvPOK( ssv ) ) {
+ memset(&val, 0, sizeof(val));
+ g_value_init(&val, G_TYPE_STRING);
+ g_value_set_string(&val, SvPV(ssv,PL_na));
+ lu_ent_clear(self, LU_LOGINSHELL);
+ lu_ent_add(self, LU_LOGINSHELL, &val);
+ } else {
+ warn("XS_LoginShell: Cannot make operation on LU_LOGINSHELL attribute");
+ }
+
+void
+Ent_ShadowPass(self, ssv)
+ USER::ENT *self
+ SV *ssv
+ PPCODE:
+ GValueArray *values;
+ GValue *value, val;
+ if ( SvIOK(ssv) && SvIV(ssv) == -65533) {
+ values = lu_ent_get(self, LU_SHADOWPASSWORD);
+ if (values != NULL) {
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_STRING(value)) {
+ XPUSHs(sv_2mortal(newSVpv(g_value_get_string(value), 0)));
+ } else if (G_VALUE_HOLDS_LONG(value)) {
+ XPUSHs(sv_2mortal(newSVpv(g_strdup_printf("%ld", g_value_get_long(value)), 0)));
+ }
+ }
+ } else if( SvPOK( ssv ) ) {
+ memset(&val, 0, sizeof(val));
+ g_value_init(&val, G_TYPE_STRING);
+ g_value_set_string(&val, SvPV(ssv,PL_na));
+ lu_ent_clear(self, LU_SHADOWPASSWORD);
+ lu_ent_add(self, LU_SHADOWPASSWORD, &val);
+ } else {
+ warn("XS_ShadowPass: Cannot make operation on LU_SHADOWPASSWORD attribute");
+ }
+
+void
+Ent_ShadowWarn(self, ssv)
+ USER::ENT *self
+ SV *ssv
+ PPCODE:
+ GValueArray *values;
+ GValue *value, val;
+ if ( SvIOK(ssv) ) {
+ if (SvIV(ssv) == -65533) {
+ values = lu_ent_get(self, LU_SHADOWWARNING);
+ if (values != NULL) {
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_LONG(value)) {
+ XPUSHs(sv_2mortal(newSViv(g_value_get_long(value))));
+ } else if (G_VALUE_HOLDS_STRING(value)) {
+ XPUSHs(sv_2mortal(newSViv(atol(g_value_get_string(value)))));
+ }
+ }
+ } else {
+ memset(&val, 0, sizeof(val));
+ g_value_init(&val, G_TYPE_LONG);
+ g_value_set_long(&val, (long)SvIV( ssv ));
+ lu_ent_clear(self, LU_SHADOWWARNING);
+ lu_ent_add(self, LU_SHADOWWARNING, &val);
+ }
+ } else {
+ warn("XS_ShadowWarn: Cannot make operation on LU_SHADOWWARNING attribute");
+ }
+
+void
+Ent_ShadowLastChange(self, ssv)
+ USER::ENT *self
+ SV *ssv
+ PPCODE:
+ GValueArray *values;
+ GValue *value, val;
+ if ( SvIOK(ssv) ) {
+ if (SvIV(ssv) == -65533) {
+ values = lu_ent_get(self, LU_SHADOWLASTCHANGE);
+ if (values != NULL) {
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_LONG(value)) {
+ XPUSHs(sv_2mortal(newSViv(g_value_get_long(value))));
+ } else if (G_VALUE_HOLDS_STRING(value)) {
+ XPUSHs(sv_2mortal(newSViv(atol(g_value_get_string(value)))));
+ }
+ }
+ } else {
+ memset(&val, 0, sizeof(val));
+ g_value_init(&val, G_TYPE_LONG);
+ g_value_set_long(&val, (long)SvIV( ssv ));
+ lu_ent_clear(self, LU_SHADOWLASTCHANGE);
+ lu_ent_add(self, LU_SHADOWLASTCHANGE, &val);
+ }
+ } else {
+ warn("XS_ShadowLastChange: Cannot make operation on LU_SHADOWLASTCHANGE attribute");
+ }
+
+void
+Ent_ShadowMin(self, ssv)
+ USER::ENT *self
+ SV *ssv
+ PPCODE:
+ GValueArray *values;
+ GValue *value, val;
+ if ( SvIOK(ssv) ) {
+ if (SvIV(ssv) == -65533) {
+ values = lu_ent_get(self, LU_SHADOWMIN);
+ if (values != NULL) {
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_LONG(value)) {
+ XPUSHs(sv_2mortal(newSViv(g_value_get_long(value))));
+ } else if (G_VALUE_HOLDS_STRING(value)) {
+ XPUSHs(sv_2mortal(newSViv(atol(g_value_get_string(value)))));
+ }
+ }
+ } else {
+ memset(&val, 0, sizeof(val));
+ g_value_init(&val, G_TYPE_LONG);
+ g_value_set_long(&val, (long)SvIV( ssv ));
+ lu_ent_clear(self, LU_SHADOWMIN);
+ lu_ent_add(self, LU_SHADOWMIN, &val);
+ }
+ } else {
+ warn("XS_ShadowMin: Cannot make operation on LU_SHADOWMIN attribute");
+ }
+
+void
+Ent_ShadowMax(self, ssv)
+ USER::ENT *self
+ SV *ssv
+ PPCODE:
+ GValueArray *values;
+ GValue *value, val;
+ if ( SvIOK(ssv) ) {
+ if (SvIV(ssv) == -65533) {
+ values = lu_ent_get(self, LU_SHADOWMAX);
+ if (values != NULL) {
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_LONG(value)) {
+ XPUSHs(sv_2mortal(newSViv(g_value_get_long(value))));
+ } else if (G_VALUE_HOLDS_STRING(value)) {
+ XPUSHs(sv_2mortal(newSViv(atol(g_value_get_string(value)))));
+ }
+ }
+ } else {
+ memset(&val, 0, sizeof(val));
+ g_value_init(&val, G_TYPE_LONG);
+ g_value_set_long(&val, (long)SvIV( ssv ));
+ lu_ent_clear(self, LU_SHADOWMAX);
+ lu_ent_add(self, LU_SHADOWMAX, &val);
+ }
+ } else {
+ warn("XS_ShadowMax: Cannot make operation on LU_SHADOWMAX attribute");
+ }
+
+void
+Ent_ShadowInact(self, ssv)
+ USER::ENT *self
+ SV *ssv
+ PPCODE:
+ GValueArray *values;
+ GValue *value, val;
+ if ( SvIOK(ssv) ) {
+ if (SvIV(ssv) == -65533) {
+ values = lu_ent_get(self, LU_SHADOWINACTIVE);
+ if (values != NULL) {
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_LONG(value)) {
+ XPUSHs(sv_2mortal(newSViv(g_value_get_long(value))));
+ } else if (G_VALUE_HOLDS_STRING(value)) {
+ XPUSHs(sv_2mortal(newSViv(atol(g_value_get_string(value)))));
+ }
+ }
+ } else {
+ memset(&val, 0, sizeof(val));
+ g_value_init(&val, G_TYPE_LONG);
+ g_value_set_long(&val, (long)SvIV( ssv ));
+ lu_ent_clear(self, LU_SHADOWINACTIVE);
+ lu_ent_add(self, LU_SHADOWINACTIVE, &val);
+ }
+ } else {
+ warn("XS_ShadowInact: Cannot make operation on LU_SHADOWINACTIVE attribute");
+ }
+
+void
+Ent_ShadowExpire(self, ssv)
+ USER::ENT *self
+ SV *ssv
+ PPCODE:
+ GValueArray *values;
+ GValue *value, val;
+ if ( SvIOK(ssv) ) {
+ if (SvIV(ssv) == -65533) {
+ values = lu_ent_get(self, LU_SHADOWEXPIRE);
+ if (values != NULL) {
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_LONG(value)) {
+ XPUSHs(sv_2mortal(newSViv(g_value_get_long(value))));
+ } else if (G_VALUE_HOLDS_STRING(value)) {
+ XPUSHs(sv_2mortal(newSViv(atol(g_value_get_string(value)))));
+ }
+ }
+ }
+ } else if (SvNOK(ssv)) {
+ memset(&val, 0, sizeof(val));
+ g_value_init(&val, G_TYPE_LONG);
+ g_value_set_long(&val, (long)SvNV( ssv ));
+ lu_ent_clear(self, LU_SHADOWEXPIRE);
+ lu_ent_add(self, LU_SHADOWEXPIRE, &val);
+ } else {
+ warn("XS_ShadowExpire: Cannot make operation on LU_SHADOWEXPIRE attribute");
+ }
+
+void
+Ent_ShadowFlag(self, ssv)
+ USER::ENT *self
+ SV *ssv
+ PPCODE:
+ GValueArray *values;
+ GValue *value, val;
+ if ( SvIOK(ssv) ) {
+ if ( SvIV(ssv) == -65533 ) {
+ values = lu_ent_get(self, LU_SHADOWFLAG);
+ if (values != NULL) {
+ value = g_value_array_get_nth(values, 0);
+ if (G_VALUE_HOLDS_LONG(value)) {
+ XPUSHs(sv_2mortal(newSViv(g_value_get_long(value))));
+ } else if (G_VALUE_HOLDS_STRING(value)) {
+ XPUSHs(sv_2mortal(newSViv(atol(g_value_get_string(value)))));
+ }
+ }
+ } else {
+ memset(&val, 0, sizeof(val));
+ g_value_init(&val, G_TYPE_LONG);
+ g_value_set_long(&val, (long)SvIV( ssv ));
+ lu_ent_clear(self, LU_SHADOWFLAG);
+ lu_ent_add(self, LU_SHADOWFLAG, &val);
+ }
+ } else {
+ warn("XS_ShadowExpire: Cannot make operation on LU_SHADOWEXPIRE attribute");
+ }
+
+MODULE = USER PACKAGE = USER PREFIX = User_
+
+void
+User_ReadConfigFiles()
+ CODE:
+ /*force read of /etc/sysconfig/userdrakefilter*/
+
diff --git a/USER/ppport.h b/USER/ppport.h
new file mode 100644
index 0000000..b32df9c
--- /dev/null
+++ b/USER/ppport.h
@@ -0,0 +1,540 @@
+
+/* ppport.h -- Perl/Pollution/Portability Version 2.0002
+ *
+ * Automatically Created by Devel::PPPort on Fri Feb 28 15:36:17 2003
+ *
+ * Do NOT edit this file directly! -- Edit PPPort.pm instead.
+ *
+ * Version 2.x, Copyright (C) 2001, Paul Marquess.
+ * Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
+ * This code may be used and distributed under the same license as any
+ * version of Perl.
+ *
+ * This version of ppport.h is designed to support operation with Perl
+ * installations back to 5.004, and has been tested up to 5.8.0.
+ *
+ * If this version of ppport.h is failing during the compilation of this
+ * module, please check if a newer version of Devel::PPPort is available
+ * on CPAN before sending a bug report.
+ *
+ * If you are using the latest version of Devel::PPPort and it is failing
+ * during compilation of this module, please send a report to perlbug@perl.com
+ *
+ * Include all following information:
+ *
+ * 1. The complete output from running "perl -V"
+ *
+ * 2. This file.
+ *
+ * 3. The name & version of the module you were trying to build.
+ *
+ * 4. A full log of the build that failed.
+ *
+ * 5. Any other information that you think could be relevant.
+ *
+ *
+ * For the latest version of this code, please retreive the Devel::PPPort
+ * module from CPAN.
+ *
+ */
+
+/*
+ * In order for a Perl extension module to be as portable as possible
+ * across differing versions of Perl itself, certain steps need to be taken.
+ * Including this header is the first major one, then using dTHR is all the
+ * appropriate places and using a PL_ prefix to refer to global Perl
+ * variables is the second.
+ *
+ */
+
+
+/* If you use one of a few functions that were not present in earlier
+ * versions of Perl, please add a define before the inclusion of ppport.h
+ * for a static include, or use the GLOBAL request in a single module to
+ * produce a global definition that can be referenced from the other
+ * modules.
+ *
+ * Function: Static define: Extern define:
+ * newCONSTSUB() NEED_newCONSTSUB NEED_newCONSTSUB_GLOBAL
+ *
+ */
+
+
+/* To verify whether ppport.h is needed for your module, and whether any
+ * special defines should be used, ppport.h can be run through Perl to check
+ * your source code. Simply say:
+ *
+ * perl -x ppport.h *.c *.h *.xs foo/bar*.c [etc]
+ *
+ * The result will be a list of patches suggesting changes that should at
+ * least be acceptable, if not necessarily the most efficient solution, or a
+ * fix for all possible problems. It won't catch where dTHR is needed, and
+ * doesn't attempt to account for global macro or function definitions,
+ * nested includes, typemaps, etc.
+ *
+ * In order to test for the need of dTHR, please try your module under a
+ * recent version of Perl that has threading compiled-in.
+ *
+ */
+
+
+/*
+#!/usr/bin/perl
+@ARGV = ("*.xs") if !@ARGV;
+%badmacros = %funcs = %macros = (); $replace = 0;
+foreach (<DATA>) {
+ $funcs{$1} = 1 if /Provide:\s+(\S+)/;
+ $macros{$1} = 1 if /^#\s*define\s+([a-zA-Z0-9_]+)/;
+ $replace = $1 if /Replace:\s+(\d+)/;
+ $badmacros{$2}=$1 if $replace and /^#\s*define\s+([a-zA-Z0-9_]+).*?\s+([a-zA-Z0-9_]+)/;
+ $badmacros{$1}=$2 if /Replace (\S+) with (\S+)/;
+}
+foreach $filename (map(glob($_),@ARGV)) {
+ unless (open(IN, "<$filename")) {
+ warn "Unable to read from $file: $!\n";
+ next;
+ }
+ print "Scanning $filename...\n";
+ $c = ""; while (<IN>) { $c .= $_; } close(IN);
+ $need_include = 0; %add_func = (); $changes = 0;
+ $has_include = ($c =~ /#.*include.*ppport/m);
+
+ foreach $func (keys %funcs) {
+ if ($c =~ /#.*define.*\bNEED_$func(_GLOBAL)?\b/m) {
+ if ($c !~ /\b$func\b/m) {
+ print "If $func isn't needed, you don't need to request it.\n" if
+ $changes += ($c =~ s/^.*#.*define.*\bNEED_$func\b.*\n//m);
+ } else {
+ print "Uses $func\n";
+ $need_include = 1;
+ }
+ } else {
+ if ($c =~ /\b$func\b/m) {
+ $add_func{$func} =1 ;
+ print "Uses $func\n";
+ $need_include = 1;
+ }
+ }
+ }
+
+ if (not $need_include) {
+ foreach $macro (keys %macros) {
+ if ($c =~ /\b$macro\b/m) {
+ print "Uses $macro\n";
+ $need_include = 1;
+ }
+ }
+ }
+
+ foreach $badmacro (keys %badmacros) {
+ if ($c =~ /\b$badmacro\b/m) {
+ $changes += ($c =~ s/\b$badmacro\b/$badmacros{$badmacro}/gm);
+ print "Uses $badmacros{$badmacro} (instead of $badmacro)\n";
+ $need_include = 1;
+ }
+ }
+
+ if (scalar(keys %add_func) or $need_include != $has_include) {
+ if (!$has_include) {
+ $inc = join('',map("#define NEED_$_\n", sort keys %add_func)).
+ "#include \"ppport.h\"\n";
+ $c = "$inc$c" unless $c =~ s/#.*include.*XSUB.*\n/$&$inc/m;
+ } elsif (keys %add_func) {
+ $inc = join('',map("#define NEED_$_\n", sort keys %add_func));
+ $c = "$inc$c" unless $c =~ s/^.*#.*include.*ppport.*$/$inc$&/m;
+ }
+ if (!$need_include) {
+ print "Doesn't seem to need ppport.h.\n";
+ $c =~ s/^.*#.*include.*ppport.*\n//m;
+ }
+ $changes++;
+ }
+
+ if ($changes) {
+ open(OUT,">/tmp/ppport.h.$$");
+ print OUT $c;
+ close(OUT);
+ open(DIFF, "diff -u $filename /tmp/ppport.h.$$|");
+ while (<DIFF>) { s!/tmp/ppport\.h\.$$!$filename.patched!; print STDOUT; }
+ close(DIFF);
+ unlink("/tmp/ppport.h.$$");
+ } else {
+ print "Looks OK\n";
+ }
+}
+__DATA__
+*/
+
+#ifndef _P_P_PORTABILITY_H_
+#define _P_P_PORTABILITY_H_
+
+#ifndef PERL_REVISION
+# ifndef __PATCHLEVEL_H_INCLUDED__
+# include "patchlevel.h"
+# endif
+# ifndef PERL_REVISION
+# define PERL_REVISION (5)
+ /* Replace: 1 */
+# define PERL_VERSION PATCHLEVEL
+# define PERL_SUBVERSION SUBVERSION
+ /* Replace PERL_PATCHLEVEL with PERL_VERSION */
+ /* Replace: 0 */
+# endif
+#endif
+
+#define PERL_BCDVERSION ((PERL_REVISION * 0x1000000L) + (PERL_VERSION * 0x1000L) + PERL_SUBVERSION)
+
+/* It is very unlikely that anyone will try to use this with Perl 6
+ (or greater), but who knows.
+ */
+#if PERL_REVISION != 5
+# error ppport.h only works with Perl version 5
+#endif /* PERL_REVISION != 5 */
+
+#ifndef ERRSV
+# define ERRSV perl_get_sv("@",FALSE)
+#endif
+
+#if (PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 5))
+/* Replace: 1 */
+# define PL_Sv Sv
+# define PL_compiling compiling
+# define PL_copline copline
+# define PL_curcop curcop
+# define PL_curstash curstash
+# define PL_defgv defgv
+# define PL_dirty dirty
+# define PL_dowarn dowarn
+# define PL_hints hints
+# define PL_na na
+# define PL_perldb perldb
+# define PL_rsfp_filters rsfp_filters
+# define PL_rsfpv rsfp
+# define PL_stdingv stdingv
+# define PL_sv_no sv_no
+# define PL_sv_undef sv_undef
+# define PL_sv_yes sv_yes
+/* Replace: 0 */
+#endif
+
+#ifdef HASATTRIBUTE
+# if defined(__GNUC__) && defined(__cplusplus)
+# define PERL_UNUSED_DECL
+# else
+# define PERL_UNUSED_DECL __attribute__((unused))
+# endif
+#else
+# define PERL_UNUSED_DECL
+#endif
+
+#ifndef dNOOP
+# define NOOP (void)0
+# define dNOOP extern int Perl___notused PERL_UNUSED_DECL
+#endif
+
+#ifndef dTHR
+# define dTHR dNOOP
+#endif
+
+#ifndef dTHX
+# define dTHX dNOOP
+# define dTHXa(x) dNOOP
+# define dTHXoa(x) dNOOP
+#endif
+
+#ifndef pTHX
+# define pTHX void
+# define pTHX_
+# define aTHX
+# define aTHX_
+#endif
+
+#ifndef UVSIZE
+# define UVSIZE IVSIZE
+#endif
+
+#ifndef NVTYPE
+# if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE)
+# define NVTYPE long double
+# else
+# define NVTYPE double
+# endif
+typedef NVTYPE NV;
+#endif
+
+#ifndef INT2PTR
+
+#if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
+# define PTRV UV
+# define INT2PTR(any,d) (any)(d)
+#else
+# if PTRSIZE == LONGSIZE
+# define PTRV unsigned long
+# else
+# define PTRV unsigned
+# endif
+# define INT2PTR(any,d) (any)(PTRV)(d)
+#endif
+#define NUM2PTR(any,d) (any)(PTRV)(d)
+#define PTR2IV(p) INT2PTR(IV,p)
+#define PTR2UV(p) INT2PTR(UV,p)
+#define PTR2NV(p) NUM2PTR(NV,p)
+#if PTRSIZE == LONGSIZE
+# define PTR2ul(p) (unsigned long)(p)
+#else
+# define PTR2ul(p) INT2PTR(unsigned long,p)
+#endif
+
+#endif /* !INT2PTR */
+
+#ifndef boolSV
+# define boolSV(b) ((b) ? &PL_sv_yes : &PL_sv_no)
+#endif
+
+#ifndef gv_stashpvn
+# define gv_stashpvn(str,len,flags) gv_stashpv(str,flags)
+#endif
+
+#ifndef newSVpvn
+# define newSVpvn(data,len) ((len) ? newSVpv ((data), (len)) : newSVpv ("", 0))
+#endif
+
+#ifndef newRV_inc
+/* Replace: 1 */
+# define newRV_inc(sv) newRV(sv)
+/* Replace: 0 */
+#endif
+
+/* DEFSV appears first in 5.004_56 */
+#ifndef DEFSV
+# define DEFSV GvSV(PL_defgv)
+#endif
+
+#ifndef SAVE_DEFSV
+# define SAVE_DEFSV SAVESPTR(GvSV(PL_defgv))
+#endif
+
+#ifndef newRV_noinc
+# ifdef __GNUC__
+# define newRV_noinc(sv) \
+ ({ \
+ SV *nsv = (SV*)newRV(sv); \
+ SvREFCNT_dec(sv); \
+ nsv; \
+ })
+# else
+# if defined(USE_THREADS)
+static SV * newRV_noinc (SV * sv)
+{
+ SV *nsv = (SV*)newRV(sv);
+ SvREFCNT_dec(sv);
+ return nsv;
+}
+# else
+# define newRV_noinc(sv) \
+ (PL_Sv=(SV*)newRV(sv), SvREFCNT_dec(sv), (SV*)PL_Sv)
+# endif
+# endif
+#endif
+
+/* Provide: newCONSTSUB */
+
+/* newCONSTSUB from IO.xs is in the core starting with 5.004_63 */
+#if (PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION < 63))
+
+#if defined(NEED_newCONSTSUB)
+static
+#else
+extern void newCONSTSUB(HV * stash, char * name, SV *sv);
+#endif
+
+#if defined(NEED_newCONSTSUB) || defined(NEED_newCONSTSUB_GLOBAL)
+void
+newCONSTSUB(stash,name,sv)
+HV *stash;
+char *name;
+SV *sv;
+{
+ U32 oldhints = PL_hints;
+ HV *old_cop_stash = PL_curcop->cop_stash;
+ HV *old_curstash = PL_curstash;
+ line_t oldline = PL_curcop->cop_line;
+ PL_curcop->cop_line = PL_copline;
+
+ PL_hints &= ~HINT_BLOCK_SCOPE;
+ if (stash)
+ PL_curstash = PL_curcop->cop_stash = stash;
+
+ newSUB(
+
+#if (PERL_VERSION < 3) || ((PERL_VERSION == 3) && (PERL_SUBVERSION < 22))
+ /* before 5.003_22 */
+ start_subparse(),
+#else
+# if (PERL_VERSION == 3) && (PERL_SUBVERSION == 22)
+ /* 5.003_22 */
+ start_subparse(0),
+# else
+ /* 5.003_23 onwards */
+ start_subparse(FALSE, 0),
+# endif
+#endif
+
+ newSVOP(OP_CONST, 0, newSVpv(name,0)),
+ newSVOP(OP_CONST, 0, &PL_sv_no), /* SvPV(&PL_sv_no) == "" -- GMB */
+ newSTATEOP(0, Nullch, newSVOP(OP_CONST, 0, sv))
+ );
+
+ PL_hints = oldhints;
+ PL_curcop->cop_stash = old_cop_stash;
+ PL_curstash = old_curstash;
+ PL_curcop->cop_line = oldline;
+}
+#endif
+
+#endif /* newCONSTSUB */
+
+#ifndef START_MY_CXT
+
+/*
+ * Boilerplate macros for initializing and accessing interpreter-local
+ * data from C. All statics in extensions should be reworked to use
+ * this, if you want to make the extension thread-safe. See ext/re/re.xs
+ * for an example of the use of these macros.
+ *
+ * Code that uses these macros is responsible for the following:
+ * 1. #define MY_CXT_KEY to a unique string, e.g. "DynaLoader_guts"
+ * 2. Declare a typedef named my_cxt_t that is a structure that contains
+ * all the data that needs to be interpreter-local.
+ * 3. Use the START_MY_CXT macro after the declaration of my_cxt_t.
+ * 4. Use the MY_CXT_INIT macro such that it is called exactly once
+ * (typically put in the BOOT: section).
+ * 5. Use the members of the my_cxt_t structure everywhere as
+ * MY_CXT.member.
+ * 6. Use the dMY_CXT macro (a declaration) in all the functions that
+ * access MY_CXT.
+ */
+
+#if defined(MULTIPLICITY) || defined(PERL_OBJECT) || \
+ defined(PERL_CAPI) || defined(PERL_IMPLICIT_CONTEXT)
+
+/* This must appear in all extensions that define a my_cxt_t structure,
+ * right after the definition (i.e. at file scope). The non-threads
+ * case below uses it to declare the data as static. */
+#define START_MY_CXT
+
+#if (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION < 68 ))
+/* Fetches the SV that keeps the per-interpreter data. */
+#define dMY_CXT_SV \
+ SV *my_cxt_sv = perl_get_sv(MY_CXT_KEY, FALSE)
+#else /* >= perl5.004_68 */
+#define dMY_CXT_SV \
+ SV *my_cxt_sv = *hv_fetch(PL_modglobal, MY_CXT_KEY, \
+ sizeof(MY_CXT_KEY)-1, TRUE)
+#endif /* < perl5.004_68 */
+
+/* This declaration should be used within all functions that use the
+ * interpreter-local data. */
+#define dMY_CXT \
+ dMY_CXT_SV; \
+ my_cxt_t *my_cxtp = INT2PTR(my_cxt_t*,SvUV(my_cxt_sv))
+
+/* Creates and zeroes the per-interpreter data.
+ * (We allocate my_cxtp in a Perl SV so that it will be released when
+ * the interpreter goes away.) */
+#define MY_CXT_INIT \
+ dMY_CXT_SV; \
+ /* newSV() allocates one more than needed */ \
+ my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\
+ Zero(my_cxtp, 1, my_cxt_t); \
+ sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
+
+/* This macro must be used to access members of the my_cxt_t structure.
+ * e.g. MYCXT.some_data */
+#define MY_CXT (*my_cxtp)
+
+/* Judicious use of these macros can reduce the number of times dMY_CXT
+ * is used. Use is similar to pTHX, aTHX etc. */
+#define pMY_CXT my_cxt_t *my_cxtp
+#define pMY_CXT_ pMY_CXT,
+#define _pMY_CXT ,pMY_CXT
+#define aMY_CXT my_cxtp
+#define aMY_CXT_ aMY_CXT,
+#define _aMY_CXT ,aMY_CXT
+
+#else /* single interpreter */
+
+
+#define START_MY_CXT static my_cxt_t my_cxt;
+#define dMY_CXT_SV dNOOP
+#define dMY_CXT dNOOP
+#define MY_CXT_INIT NOOP
+#define MY_CXT my_cxt
+
+#define pMY_CXT void
+#define pMY_CXT_
+#define _pMY_CXT
+#define aMY_CXT
+#define aMY_CXT_
+#define _aMY_CXT
+
+#endif
+
+#endif /* START_MY_CXT */
+
+#ifndef IVdf
+# if IVSIZE == LONGSIZE
+# define IVdf "ld"
+# define UVuf "lu"
+# define UVof "lo"
+# define UVxf "lx"
+# define UVXf "lX"
+# else
+# if IVSIZE == INTSIZE
+# define IVdf "d"
+# define UVuf "u"
+# define UVof "o"
+# define UVxf "x"
+# define UVXf "X"
+# endif
+# endif
+#endif
+
+#ifndef NVef
+# if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) && \
+ defined(PERL_PRIfldbl) /* Not very likely, but let's try anyway. */
+# define NVef PERL_PRIeldbl
+# define NVff PERL_PRIfldbl
+# define NVgf PERL_PRIgldbl
+# else
+# define NVef "e"
+# define NVff "f"
+# define NVgf "g"
+# endif
+#endif
+
+#ifndef AvFILLp /* Older perls (<=5.003) lack AvFILLp */
+# define AvFILLp AvFILL
+#endif
+
+#ifdef SvPVbyte
+# if PERL_REVISION == 5 && PERL_VERSION < 7
+ /* SvPVbyte does not work in perl-5.6.1, borrowed version for 5.7.3 */
+# undef SvPVbyte
+# define SvPVbyte(sv, lp) \
+ ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8)) == (SVf_POK) \
+ ? ((lp = SvCUR(sv)), SvPVX(sv)) : my_sv_2pvbyte(aTHX_ sv, &lp))
+ static char *
+ my_sv_2pvbyte(pTHX_ register SV *sv, STRLEN *lp)
+ {
+ sv_utf8_downgrade(sv,0);
+ return SvPV(sv,*lp);
+ }
+# endif
+#else
+# define SvPVbyte SvPV
+#endif
+
+#endif /* _P_P_PORTABILITY_H_ */
+
+/* End of File ppport.h */
diff --git a/USER/typemap b/USER/typemap
new file mode 100644
index 0000000..797b6c5
--- /dev/null
+++ b/USER/typemap
@@ -0,0 +1,5 @@
+TYPEMAP
+
+USER::ADMIN * O_OBJECT
+USER::ENT * O_OBJECT
+USER__ERR * T_PTROBJ