ACC SHELL
#! /usr/bin/perl -w
#
# Example of plugin module
# This is the API part of UsersPluginLDAPAll plugin - configuration of
# all user/group LDAP attributes
#
package UsersPluginLDAPAll;
use strict;
use YaST::YCP qw(:LOGGING);
use YaPI;
use Data::Dumper;
textdomain("users");
our %TYPEINFO;
##--------------------------------------
##--------------------- global imports
YaST::YCP::Import ("SCR");
YaST::YCP::Import ("Ldap");
##--------------------------------------
##--------------------- global variables
# default object classes of LDAP users
my @user_object_class =
("top","posixAccount", "inetOrgPerson");
# default object classes of LDAP groups
my @group_object_class =
( "top", "posixGroup", "groupOfNames");
# object classes of LDAP groups using uniqmember attribute
my @unique_group_object_class =
( "top", "posixGroup", "groupOfUniqueNames");
# error message, returned when some plugin function fails
my $error = "";
##--------------------------------------
# All functions have 2 "any" parameters: this will probably mean
# 1st: configuration map (hash) - e.g. saying if we work with user or group
# 2nd: data map (hash) of user (group) to work with
# in 'config' map there is a info of this type:
# "what" => "user" / "group"
# "modified" => "added"/"edited"/"deleted"
# "enabled" => 1/ key not present
# "disabled" => 1/ key not present
# "plugins_to_remove" => list of plugins which has to be removed
# 'data' map contains the atrtributes of the user. It could also contain
# some keys, which Users module uses internaly (like 'groupname' for name of
# user's default group). Just ignore these values
# -- Warning messages --
# There is a special way, when you want to give user additional information
# (warning) about some issues appeared during the function.
#
# These keys can be saved by plugin to the result structure of AddBefore,
# Add, EditBefore, Edit, Enable, Disable calls:
# "warning_message" => STRING
# Translated message that should be shown to user (probably as a popup)
# "warning_message_ID" => STRING
# The ID of the message (optional).
#
# This key can be present in user/group $data hash:
# "confirmed_warnings" => HASH (in the form { message_ID_1 => 1 })
# (This has sense only if plugin uses optional "warning_message_ID" key)
# Indicates which messages were already shown to this user/group.
# Plugin function may check for existence of the message_ID_1 in this
# hash before generating "warning_message", to realize if this message
# was alredy shown before (in the same situation).
# See example in AddBefore function.
##------------------------------------
# return names of provided functions
BEGIN { $TYPEINFO{Interface} = ["function", ["list", "string"], "any", "any"];}
sub Interface {
my $self = shift;
my @interface = (
"GUIClient",
"Check",
"Name",
"Summary",
"Restriction",
"WriteBefore",
"Write",
"AddBefore",
"Add",
"EditBefore",
"Edit",
"Interface",
"Disable",
"Enable",
"PluginPresent",
"PluginRemovable",
# "InternalAttributes",
"Error",
);
return \@interface;
}
# return error message, generated by plugin
BEGIN { $TYPEINFO{Error} = ["function", "string", "any", "any"];}
sub Error {
my $self = shift;
return $error;
}
# return plugin name, used for GUI (translated)
BEGIN { $TYPEINFO{Name} = ["function", "string", "any", "any"];}
sub Name {
my $self = shift;
# plugin name
return __("LDAP Attributes");
}
##------------------------------------
# return plugin summary (to be shown in table with all plugins)
BEGIN { $TYPEINFO{Summary} = ["function", "string", "any", "any"];}
sub Summary {
my $self = shift;
my $what = "user";
# plugin summary (table item)
my $ret = __("Edit Remaining LDAP Attributes");
if (defined $_[0]->{"what"} && $_[0]->{"what"} eq "group") {
# plugin summary (table item)
$ret = __("Edit Remaining LDAP Attributes");
}
return $ret;
}
##------------------------------------
# return plugin internal attributes (which shouldn't be shown to user)
BEGIN { $TYPEINFO{InternalAttributes} = ["function",
[ "list", "string" ], "any", "any"];
}
sub InternalAttributes {
my $self = shift;
my @ret = ();
if (defined $_[0]->{"what"} && $_[0]->{"what"} eq "group") {
@ret = ();
}
return \@ret;
}
##------------------------------------
# checks the current data map of user/group (2nd parameter) and returns
# true if given user (group) has our plugin
BEGIN { $TYPEINFO{PluginPresent} = ["function", "boolean", "any", "any"];}
sub PluginPresent {
my $self = shift;
# Yes, all LDAP users/groups have this plugin as default
# (and this plugin is used only for LDAP objects, see Restriction function)
return YaST::YCP::Boolean (1);
}
##------------------------------------
# Is it possible to remove this plugin from user/group?
BEGIN { $TYPEINFO{PluginRemovable} = ["function", "boolean", "any", "any"];}
sub PluginRemovable {
# No, this plugin must be present for all LDAP objects
return YaST::YCP::Boolean (0);
}
##------------------------------------
# return name of YCP client defining YCP GUI
BEGIN { $TYPEINFO{GUIClient} = ["function", "string", "any", "any"];}
sub GUIClient {
my $self = shift;
return "users_plugin_ldap_all";
}
##------------------------------------
# Type of objects this plugin is restricted to.
# It defines:
# 1. type of objects which it should be applied to (ldap/nis/local/system)
# 2. type of objects at all (user/group)
# If this function doesn't exist, plugin is applied for all users of all types
BEGIN { $TYPEINFO{Restriction} = ["function",
["map", "string", "any"], "any", "any"];}
sub Restriction {
my $self = shift;
return {
# This plugin applies only for LDAP entries,
"ldap" => 1,
# both for users and groups:
"user" => 1,
"group" => 1
};
}
##------------------------------------
# check if all required atributes of LDAP entry are present
# parameter is (whole) map of entry (user/group)
# return error message
BEGIN { $TYPEINFO{Check} = ["function",
"string",
"any",
"any"];
}
sub Check {
my $self = shift;
my $config = $_[0];
my $data = $_[1];
# attribute conversion
my @required_attrs = ();
my @object_classes = ();
if (defined $data->{"objectClass"} && ref ($data->{"objectClass"}) eq "ARRAY") {
@object_classes = @{$data->{"objectClass"}};
}
# get the attributes required for entry's object classes
foreach my $class (@object_classes) {
my $req = Ldap->GetRequiredAttributes ($class);
if (defined $req && ref ($req) eq "ARRAY") {
foreach my $r (@{$req}) {
if (!contains (\@required_attrs, $r, 1)) {
push @required_attrs, $r;
}
}
}
}
my $action = $data->{"what"} || "";
# check the presence of required attributes
foreach my $req (@required_attrs) {
my $val = $data->{$req};
if (substr ($action, 0, 5) eq "edit_" && !defined $val) {
# when editing using YaPI, attribute dosn't have to be loaded
next;
}
if (!defined $val || $val eq "" ||
(ref ($val) eq "ARRAY" &&
((@{$val} == 0) || (@{$val} == 1 && $val->[0] eq "")))) {
# error popup (user forgot to fill in some attributes)
return sprintf (__("The attribute '%s' is required for this object according
to its LDAP configuration, but it is currently empty."), $req);
}
}
return "";
}
# this will be called from Users::EnableUser
BEGIN { $TYPEINFO{Enable} = ["function",
["map", "string", "any"],
"any", "any"];
}
sub Enable {
my ($self, $config, $data) = @_;
y2debug ("Enable LDAPAll called");
return $data;
}
# this will be called from Users::DisableUser
BEGIN { $TYPEINFO{Disable} = ["function",
["map", "string", "any"],
"any", "any"];
}
sub Disable {
my ($self, $config, $data) = @_;
y2debug ("Disable LDAPAll called");
return $data;
}
# internal function:
# check if given key (second parameter) is contained in a list (1st parameter)
# if 3rd parameter is true (>0), ignore case
sub contains {
my ( $list, $key, $ignorecase ) = @_;
if ( $ignorecase ) {
if ( grep /^$key$/i, @{$list} ) {
return 1;
}
} else {
if ( grep /^$key$/, @{$list} ) {
return 1;
}
}
return 0;
}
# update the list of current object classes
sub update_object_classes {
my $config = $_[0];
my $data = $_[1];
# define the object class for new user/groupa
my @orig_object_class = ();
if (defined $data->{"objectClass"} && ref $data->{"objectClass"} eq "ARRAY")
{
@orig_object_class = @{$data->{"objectClass"}};
}
my @ocs = @user_object_class;
if (($config->{"what"} || "") eq "group") {
if (lc (Ldap->member_attribute ()) eq "uniquemember") {
@ocs = @unique_group_object_class;
}
else {
@ocs = @group_object_class;
}
}
foreach my $oc (@ocs) {
if (!contains (\@orig_object_class, $oc, 1)) {
push @orig_object_class, $oc;
}
}
$data->{"objectClass"} = \@orig_object_class;
return $data;
}
# this will be called at the beggining of Users::Add
# Could be called multiple times for one user/group!
BEGIN { $TYPEINFO{AddBefore} = ["function",
["map", "string", "any"],
"any", "any"];
}
sub AddBefore {
my $self = shift;
my $config = $_[0];
my $data = $_[1]; # only new data that will be copied to current user map
$data = update_object_classes ($config, $data);
y2debug ("AddBefore LDAPAll called");
my $warning_id = "something_wrong";
my $warning = __("An error occurred.");
if (ref ($data->{"confirmed_warnings"}) eq "HASH" &&
defined $data->{"confirmed_warnings"}{$warning_id}) {
y2debug ("warning already shown");
}
elsif (0) {
$data->{"warning_message"} = $warning;
$data->{"warning_message_ID"} = $warning_id;
}
return $data;
}
# This will be called just after Users::Add - the data map probably contains
# the values which we could use to create new ones
# Could be called multiple times for one user/group!
BEGIN { $TYPEINFO{Add} = ["function", ["map", "string", "any"], "any", "any"];}
sub Add {
my $self = shift;
my $config = $_[0];
my $data = $_[1]; # the whole map of current user/group after Users::Edit
y2debug("Add LDAPAll called");
return $data;
}
# this will be called at the beggining of Users::Edit
BEGIN { $TYPEINFO{EditBefore} = ["function",
["map", "string", "any"],
"any", "any"];
}
sub EditBefore {
my $self = shift;
my $config = $_[0];
my $data = $_[1]; # only new data that will be copied to current user map
# data of original user/group are saved as a submap of $config
# data with key "org_data"
# in $data hash, there could be "plugins_to_remove": list of plugins which
# has to be removed from the user
y2debug ("EditBefore LDAPAll called");
return $data;
}
# this will be called just after Users::Edit
BEGIN { $TYPEINFO{Edit} = ["function",
["map", "string", "any"],
"any", "any"];
}
sub Edit {
my $self = shift;
my $config = $_[0];
my $data = $_[1]; # the whole map of current user/group after Users::Edit
# in $data hash, there could be "plugins_to_remove": list of plugins which
# has to be removed from the user
y2debug ("Edit LDAPAll called");
return $data;
}
# what should be done before user is finally written to LDAP
BEGIN { $TYPEINFO{WriteBefore} = ["function", "boolean", "any", "any"];}
sub WriteBefore {
my $self = shift;
my $config = $_[0];
my $data = $_[1];
# this means what was done with a user/group: added/edited/deleted
my $action = $config->{"modified"} || "";
y2debug ("WriteBefore LDAPAll called");
return YaST::YCP::Boolean (1);
}
# what should be done after user is finally written to LDAP
BEGIN { $TYPEINFO{Write} = ["function", "boolean", "any", "any"];}
sub Write {
my $self = shift;
my $config = $_[0];
my $data = $_[1];
# this means what was done with a user: added/edited/deleted
my $action = $config->{"modified"} || "";
y2debug ("Write LDAPAll called");
return YaST::YCP::Boolean (1);
}
1
# EOF
ACC SHELL 2018