/* Copyright (C) 2003 MandrakeSoft SA Daouda Lo (daouda at mandrakesoft dot com) * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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_generic, _("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) ; safefree((char*)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 val"); } /* 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.\n", 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) { 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, SvPV(ssv,PL_na)); 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*/