ad_gpo.c revision 16cb0969f0a9ea71524d852077d6a480740d4f12
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder/*
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder SSSD
df098122ddc81fe1cb033a151f7305c1dda2dc81Christian Maeder
b03274844ecd270f9e9331f51cc4236a33e2e671Christian Maeder Authors:
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder Yassir Elley <yelley@redhat.com>
2eeec5240b424984e3ee26296da1eeab6c6d739eChristian Maeder
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder Copyright (C) 2013 Red Hat
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder This program is free software; you can redistribute it and/or modify
e6d40133bc9f858308654afb1262b8b483ec5922Till Mossakowski it under the terms of the GNU General Public License as published by
679d3f541f7a9ede4079e045f7758873bb901872Till Mossakowski the Free Software Foundation; either version 3 of the License, or
679d3f541f7a9ede4079e045f7758873bb901872Till Mossakowski (at your option) any later version.
1bb1684c83317dfd1692ab53415027b67d8f2faeTill Mossakowski
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder This program is distributed in the hope that it will be useful,
f3faf4e4346b6224a3aaeeac11bac8b5c8932a29Christian Maeder but WITHOUT ANY WARRANTY; without even the implied warranty of
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder GNU General Public License for more details.
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder
4a8f990902448d0562fbe1a98ce685ddbd531d38Christian Maeder You should have received a copy of the GNU General Public License
f3faf4e4346b6224a3aaeeac11bac8b5c8932a29Christian Maeder along with this program. If not, see <http://www.gnu.org/licenses/>.
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder*/
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder
f3faf4e4346b6224a3aaeeac11bac8b5c8932a29Christian Maeder/*
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder * This file implements the following pair of *public* functions (see header):
74b841a4b332085d5fd79975a13313c2681ae595Christian Maeder * ad_gpo_access_send/recv: provides client-side GPO processing
74b841a4b332085d5fd79975a13313c2681ae595Christian Maeder *
f3faf4e4346b6224a3aaeeac11bac8b5c8932a29Christian Maeder * This file also implements the following pairs of *private* functions (which
010997ddd12186698c1ebdbcddb63a670552b3c2Adrián Riesco * are used by the public functions):
f3faf4e4346b6224a3aaeeac11bac8b5c8932a29Christian Maeder * ad_gpo_process_som_send/recv: populate list of gp_som objects
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder * ad_gpo_process_gpo_send/recv: populate list of gp_gpo objects
43b4c41fbb07705c9df321221ab9cb9832460407Christian Maeder * ad_gpo_process_cse_send/recv: retrieve policy file data
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder */
ba904a15082557e939db689fcfba0c68c9a4f740Christian Maeder
1bc5dccbf0083a620ae1181c717fea75e4af5e5cChristian Maeder#include <security/pam_modules.h>
7bf4436b6f9987b070033a323757b206c898c1beChristian Maeder#include <syslog.h>
e9249d3ecd51a2b6a966a58669953e58d703adc6Till Mossakowski#include <fcntl.h>
ba904a15082557e939db689fcfba0c68c9a4f740Christian Maeder#include <ini_configobj.h>
410ff490af511ffa09b52e4de631d36a154b9730Christian Maeder#include "util/util.h"
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder#include "util/strtonum.h"
ba904a15082557e939db689fcfba0c68c9a4f740Christian Maeder#include "util/child_common.h"
1842453990fed8a1bd7a5ac792d7982c1d2bfcd5Christian Maeder#include "providers/data_provider.h"
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder#include "providers/dp_backend.h"
ba904a15082557e939db689fcfba0c68c9a4f740Christian Maeder#include "providers/ad/ad_access.h"
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder#include "providers/ad/ad_common.h"
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder#include "providers/ad/ad_domain_info.h"
54ea981a0503c396c2923a1c06421c6235baf27fChristian Maeder#include "providers/ad/ad_gpo.h"
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder#include "providers/ldap/sdap_access.h"
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder#include "providers/ldap/sdap_async.h"
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder#include "providers/ldap/sdap.h"
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder#include "providers/ldap/sdap_idmap.h"
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder#include "util/util_sss_idmap.h"
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder#include <ndr.h>
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder#include <gen_ndr/security.h>
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder
ad270004874ce1d0697fb30d7309f180553bb315Christian Maeder/* == gpo-ldap constants =================================================== */
ad270004874ce1d0697fb30d7309f180553bb315Christian Maeder
410ff490af511ffa09b52e4de631d36a154b9730Christian Maeder#define AD_AT_DN "distinguishedName"
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder#define AD_AT_UAC "userAccountControl"
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder#define AD_AT_CONFIG_NC "configurationNamingContext"
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder#define AD_AT_GPLINK "gPLink"
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder#define AD_AT_GPOPTIONS "gpOptions"
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder#define AD_AT_NT_SEC_DESC "nTSecurityDescriptor"
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder#define AD_AT_CN "cn"
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder#define AD_AT_FILE_SYS_PATH "gPCFileSysPath"
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder#define AD_AT_MACHINE_EXT_NAMES "gPCMachineExtensionNames"
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder#define AD_AT_FUNC_VERSION "gPCFunctionalityVersion"
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder#define AD_AT_FLAGS "flags"
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder#define UAC_WORKSTATION_TRUST_ACCOUNT 0x00001000
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder#define AD_AGP_GUID "edacfd8f-ffb3-11d1-b41d-00a0c968f939"
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder#define AD_AUTHENTICATED_USERS_SID "S-1-5-11"
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder/* == gpo-smb constants ==================================================== */
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder#define SMB_STANDARD_URI "smb://"
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder#define BUFSIZE 65536
f1b14608f0f3db464c3aded480e49522d73b08e5Christian Maeder
9192fdd8f0e682ac0f0183dd854d5210fbfa4ec5Christian Maeder#define RIGHTS_SECTION "Privilege Rights"
f1b14608f0f3db464c3aded480e49522d73b08e5Christian Maeder#define ALLOW_LOGON_INTERACTIVE "SeInteractiveLogonRight"
f1b14608f0f3db464c3aded480e49522d73b08e5Christian Maeder#define DENY_LOGON_INTERACTIVE "SeDenyInteractiveLogonRight"
f1b14608f0f3db464c3aded480e49522d73b08e5Christian Maeder#define ALLOW_LOGON_REMOTE_INTERACTIVE "SeRemoteInteractiveLogonRight"
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder#define DENY_LOGON_REMOTE_INTERACTIVE "SeDenyRemoteInteractiveLogonRight"
9192fdd8f0e682ac0f0183dd854d5210fbfa4ec5Christian Maeder#define ALLOW_LOGON_NETWORK "SeNetworkLogonRight"
f1b14608f0f3db464c3aded480e49522d73b08e5Christian Maeder#define DENY_LOGON_NETWORK "SeDenyNetworkLogonRight"
f1b14608f0f3db464c3aded480e49522d73b08e5Christian Maeder#define ALLOW_LOGON_BATCH "SeBatchLogonRight"
f1b14608f0f3db464c3aded480e49522d73b08e5Christian Maeder#define DENY_LOGON_BATCH "SeDenyBatchLogonRight"
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder#define ALLOW_LOGON_SERVICE "SeServiceLogonRight"
7688e20f844fe88f75c04016841ebb5e5e3d927fChristian Maeder#define DENY_LOGON_SERVICE "SeDenyServiceLogonRight"
be3f5e3e69900ececafea5b010a8400f26af5362Christian Maeder
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maeder#define GP_EXT_GUID_SECURITY "{827D319E-6EAC-11D2-A4EA-00C04F79F83A}"
be3f5e3e69900ececafea5b010a8400f26af5362Christian Maeder#define GP_EXT_GUID_SECURITY_SUFFIX "/Machine/Microsoft/Windows NT/SecEdit/GptTmpl.inf"
12368e292c1abf7eaf975f20ee30ef7820ac5dd5Christian Maeder
12368e292c1abf7eaf975f20ee30ef7820ac5dd5Christian Maeder#ifndef SSSD_LIBEXEC_PATH
12368e292c1abf7eaf975f20ee30ef7820ac5dd5Christian Maeder#error "SSSD_LIBEXEC_PATH not defined"
be3f5e3e69900ececafea5b010a8400f26af5362Christian Maeder#else
be3f5e3e69900ececafea5b010a8400f26af5362Christian Maeder#define GPO_CHILD SSSD_LIBEXEC_PATH"/gpo_child"
be3f5e3e69900ececafea5b010a8400f26af5362Christian Maeder#endif
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maeder
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maeder/* fd used by the gpo_child process for logging */
12368e292c1abf7eaf975f20ee30ef7820ac5dd5Christian Maederint gpo_child_debug_fd = -1;
12368e292c1abf7eaf975f20ee30ef7820ac5dd5Christian Maeder
12368e292c1abf7eaf975f20ee30ef7820ac5dd5Christian Maeder/* == common data structures and declarations ============================= */
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maeder
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maederstruct gp_som {
7688e20f844fe88f75c04016841ebb5e5e3d927fChristian Maeder const char *som_dn;
be3f5e3e69900ececafea5b010a8400f26af5362Christian Maeder struct gp_gplink **gplink_list;
be3f5e3e69900ececafea5b010a8400f26af5362Christian Maeder int num_gplinks;
be3f5e3e69900ececafea5b010a8400f26af5362Christian Maeder};
8528053a6a766c3614276df0f59fb2a2e8ab6d18Christian Maeder
0d0047d6eb457b56ff10987569769a420754a56fChristian Maederstruct gp_gplink {
0d0047d6eb457b56ff10987569769a420754a56fChristian Maeder const char *gpo_dn;
0d0047d6eb457b56ff10987569769a420754a56fChristian Maeder bool enforced;
0d0047d6eb457b56ff10987569769a420754a56fChristian Maeder};
12368e292c1abf7eaf975f20ee30ef7820ac5dd5Christian Maeder
12368e292c1abf7eaf975f20ee30ef7820ac5dd5Christian Maederstruct gp_gpo {
0d0047d6eb457b56ff10987569769a420754a56fChristian Maeder struct security_descriptor *gpo_sd;
d11391a2447a2005329a95b5d770f24e62bf5b63Christian Maeder const char *gpo_dn;
12368e292c1abf7eaf975f20ee30ef7820ac5dd5Christian Maeder const char *gpo_guid;
0d0047d6eb457b56ff10987569769a420754a56fChristian Maeder const char *smb_server;
12368e292c1abf7eaf975f20ee30ef7820ac5dd5Christian Maeder const char *smb_share;
0d0047d6eb457b56ff10987569769a420754a56fChristian Maeder const char *smb_path;
0d0047d6eb457b56ff10987569769a420754a56fChristian Maeder const char **gpo_cse_guids;
0d0047d6eb457b56ff10987569769a420754a56fChristian Maeder int num_gpo_cse_guids;
278af20bd154d99e884bdf8c66d35d36699643c9Christian Maeder int gpo_func_version;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder int gpo_flags;
278af20bd154d99e884bdf8c66d35d36699643c9Christian Maeder bool send_to_child;
412aa5e819f3cd18f0be10b5571661036515b151Christian Maeder const char *policy_filename;
81337d455794a0b50fae10b53d0ed85d9e8f2fafChristian Maeder};
81337d455794a0b50fae10b53d0ed85d9e8f2fafChristian Maeder
278af20bd154d99e884bdf8c66d35d36699643c9Christian Maederenum ace_eval_status {
278af20bd154d99e884bdf8c66d35d36699643c9Christian Maeder AD_GPO_ACE_DENIED,
278af20bd154d99e884bdf8c66d35d36699643c9Christian Maeder AD_GPO_ACE_ALLOWED,
278af20bd154d99e884bdf8c66d35d36699643c9Christian Maeder AD_GPO_ACE_NEUTRAL
278af20bd154d99e884bdf8c66d35d36699643c9Christian Maeder};
278af20bd154d99e884bdf8c66d35d36699643c9Christian Maeder
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maederstruct tevent_req *ad_gpo_process_som_send(TALLOC_CTX *mem_ctx,
278af20bd154d99e884bdf8c66d35d36699643c9Christian Maeder struct tevent_context *ev,
278af20bd154d99e884bdf8c66d35d36699643c9Christian Maeder struct sdap_id_conn_ctx *conn,
278af20bd154d99e884bdf8c66d35d36699643c9Christian Maeder struct ldb_context *ldb_ctx,
81337d455794a0b50fae10b53d0ed85d9e8f2fafChristian Maeder struct sdap_id_op *sdap_op,
81337d455794a0b50fae10b53d0ed85d9e8f2fafChristian Maeder struct sdap_options *opts,
81337d455794a0b50fae10b53d0ed85d9e8f2fafChristian Maeder int timeout,
81337d455794a0b50fae10b53d0ed85d9e8f2fafChristian Maeder const char *target_dn,
81337d455794a0b50fae10b53d0ed85d9e8f2fafChristian Maeder const char *domain_name);
81337d455794a0b50fae10b53d0ed85d9e8f2fafChristian Maederint ad_gpo_process_som_recv(struct tevent_req *req,
81337d455794a0b50fae10b53d0ed85d9e8f2fafChristian Maeder TALLOC_CTX *mem_ctx,
81337d455794a0b50fae10b53d0ed85d9e8f2fafChristian Maeder struct gp_som ***som_list);
81337d455794a0b50fae10b53d0ed85d9e8f2fafChristian Maeder
412aa5e819f3cd18f0be10b5571661036515b151Christian Maederstruct tevent_req *ad_gpo_process_gpo_send(TALLOC_CTX *mem_ctx,
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder struct tevent_context *ev,
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder struct sdap_id_op *sdap_op,
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder struct sdap_options *opts,
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder char *server_hostname,
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder int timeout,
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder struct gp_som **som_list);
46947810076241f06f3e2919edb2289ed84d6c15Christian Maederint ad_gpo_process_gpo_recv(struct tevent_req *req,
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder TALLOC_CTX *mem_ctx,
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder struct gp_gpo ***candidate_gpos,
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder int *num_candidate_gpos);
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder
46947810076241f06f3e2919edb2289ed84d6c15Christian Maederstruct tevent_req *ad_gpo_process_cse_send(TALLOC_CTX *mem_ctx,
bd986fa9d0f451b8166efdb9027c153d101aa65bChristian Maeder struct tevent_context *ev,
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder bool send_to_child,
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder struct sss_domain_info *domain,
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder const char *gpo_guid,
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder const char *smb_server,
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder const char *smb_share,
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder const char *smb_path,
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder const char *smb_cse_suffix,
cc4537e2e13b93e08fc8391d3abb8e412cb71b80Christian Maeder int cached_gpt_version,
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder int gpo_timeout_option);
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder
cc4537e2e13b93e08fc8391d3abb8e412cb71b80Christian Maederint ad_gpo_process_cse_recv(struct tevent_req *req);
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder
cc4537e2e13b93e08fc8391d3abb8e412cb71b80Christian Maeder/* == ad_gpo_parse_map_options and helpers ==================================*/
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder#define GPO_LOGIN "login"
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder#define GPO_SU "su"
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder#define GPO_SU_L "su-l"
cc4537e2e13b93e08fc8391d3abb8e412cb71b80Christian Maeder#define GPO_GDM_FINGERPRINT "gdm-fingerprint"
cc4537e2e13b93e08fc8391d3abb8e412cb71b80Christian Maeder#define GPO_GDM_PASSWORD "gdm-password"
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder#define GPO_GDM_SMARTCARD "gdm-smartcard"
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder#define GPO_KDM "kdm"
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder#define GPO_SSHD "sshd"
cc4537e2e13b93e08fc8391d3abb8e412cb71b80Christian Maeder#define GPO_FTP "ftp"
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder#define GPO_SAMBA "samba"
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder#define GPO_CROND "crond"
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder#define GPO_SUDO "sudo"
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder#define GPO_SUDO_I "sudo-i"
cc4537e2e13b93e08fc8391d3abb8e412cb71b80Christian Maeder
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maederstruct gpo_map_option_entry {
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder enum gpo_map_type gpo_map_type;
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder enum ad_basic_opt ad_basic_opt;
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder const char **gpo_map_defaults;
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder const char *allow_key;
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder const char *deny_key;
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder};
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maederconst char *gpo_map_interactive_defaults[] =
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder {GPO_LOGIN, GPO_SU, GPO_SU_L,
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder GPO_GDM_FINGERPRINT, GPO_GDM_PASSWORD, GPO_GDM_SMARTCARD, GPO_KDM, NULL};
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maederconst char *gpo_map_remote_interactive_defaults[] = {GPO_SSHD, NULL};
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maederconst char *gpo_map_network_defaults[] = {GPO_FTP, GPO_SAMBA, NULL};
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maederconst char *gpo_map_batch_defaults[] = {GPO_CROND, NULL};
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maederconst char *gpo_map_service_defaults[] = {NULL};
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maederconst char *gpo_map_permit_defaults[] = {GPO_SUDO, GPO_SUDO_I, NULL};
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maederconst char *gpo_map_deny_defaults[] = {NULL};
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maederstruct gpo_map_option_entry gpo_map_option_entries[] = {
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder {GPO_MAP_INTERACTIVE, AD_GPO_MAP_INTERACTIVE, gpo_map_interactive_defaults,
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder ALLOW_LOGON_INTERACTIVE, DENY_LOGON_INTERACTIVE},
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder {GPO_MAP_REMOTE_INTERACTIVE, AD_GPO_MAP_REMOTE_INTERACTIVE,
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder gpo_map_remote_interactive_defaults,
7297175957c5ad3c0498032190b1dee9ec5fb873Christian Maeder ALLOW_LOGON_REMOTE_INTERACTIVE, DENY_LOGON_REMOTE_INTERACTIVE},
792df0347edab377785d98c63e2be8e2ce0a8bdeChristian Maeder {GPO_MAP_NETWORK, AD_GPO_MAP_NETWORK, gpo_map_network_defaults,
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder ALLOW_LOGON_NETWORK, DENY_LOGON_NETWORK},
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder {GPO_MAP_BATCH, AD_GPO_MAP_BATCH, gpo_map_batch_defaults,
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder ALLOW_LOGON_BATCH, DENY_LOGON_BATCH},
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder {GPO_MAP_SERVICE, AD_GPO_MAP_SERVICE, gpo_map_service_defaults,
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder ALLOW_LOGON_SERVICE, DENY_LOGON_SERVICE},
3f9fabb8ac5cfd9234431ecf19b51ff3e985595aChristian Maeder {GPO_MAP_PERMIT, AD_GPO_MAP_PERMIT, gpo_map_permit_defaults, NULL, NULL},
3f9fabb8ac5cfd9234431ecf19b51ff3e985595aChristian Maeder {GPO_MAP_DENY, AD_GPO_MAP_DENY, gpo_map_deny_defaults, NULL, NULL},
de66af0f4b27f08f81c7ca9c573ef9cdf7ca7a07Christian Maeder};
c30cfe2a6ab063befdfb47449bc286caee6d8fc3Christian Maeder
c30cfe2a6ab063befdfb47449bc286caee6d8fc3Christian Maederconst char* gpo_map_type_string(int gpo_map_type)
12368e292c1abf7eaf975f20ee30ef7820ac5dd5Christian Maeder{
278af20bd154d99e884bdf8c66d35d36699643c9Christian Maeder switch(gpo_map_type) {
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder case GPO_MAP_INTERACTIVE: return "Interactive";
df098122ddc81fe1cb033a151f7305c1dda2dc81Christian Maeder case GPO_MAP_REMOTE_INTERACTIVE: return "Remote Interactive";
df098122ddc81fe1cb033a151f7305c1dda2dc81Christian Maeder case GPO_MAP_NETWORK: return "Network";
df098122ddc81fe1cb033a151f7305c1dda2dc81Christian Maeder case GPO_MAP_BATCH: return "Batch";
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maeder case GPO_MAP_SERVICE: return "Service";
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maeder case GPO_MAP_PERMIT: return "Permitted";
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder case GPO_MAP_DENY: return "Denied";
1c8c2b04b40b5c054da07b8d059e5ef29d4dbc32Christian Maeder }
df098122ddc81fe1cb033a151f7305c1dda2dc81Christian Maeder return NULL;
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder}
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder
c0380b947eef252db81ee562246bb732555427f4Till Mossakowskistatic inline bool
2afae0880da7ca73c9376fd4d653ab19833fe858Christian Maederad_gpo_service_in_list(char **list, size_t nlist, const char *str)
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder{
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder size_t i;
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder
0d0047d6eb457b56ff10987569769a420754a56fChristian Maeder for (i = 0; i < nlist; i++) {
4c7f058cdd19ce67b2b5d4b7f69703d0f8a21e38Christian Maeder if (strcasecmp(list[i], str) == 0) {
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder break;
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maeder }
9192fdd8f0e682ac0f0183dd854d5210fbfa4ec5Christian Maeder }
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder
c0380b947eef252db81ee562246bb732555427f4Till Mossakowski return (i < nlist) ? true : false;
2afae0880da7ca73c9376fd4d653ab19833fe858Christian Maeder}
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder
b9804822fb178b0fc27ce967a6a8cedc42c5bf90Christian Maedererrno_t
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maederad_gpo_parse_map_option_helper(enum gpo_map_type gpo_map_type,
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder hash_key_t key,
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder hash_table_t *options_table)
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder{
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder hash_value_t val;
0d0047d6eb457b56ff10987569769a420754a56fChristian Maeder int hret;
4c7f058cdd19ce67b2b5d4b7f69703d0f8a21e38Christian Maeder int ret;
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maeder hret = hash_lookup(options_table, &key, &val);
9192fdd8f0e682ac0f0183dd854d5210fbfa4ec5Christian Maeder if (hret != HASH_SUCCESS && hret != HASH_ERROR_KEY_NOT_FOUND) {
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder DEBUG(SSSDBG_OP_FAILURE, "Error checking hash table: [%s]\n",
4c7f058cdd19ce67b2b5d4b7f69703d0f8a21e38Christian Maeder hash_error_string(hret));
4c7f058cdd19ce67b2b5d4b7f69703d0f8a21e38Christian Maeder ret = EINVAL;
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder goto done;
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski } else if (hret == HASH_SUCCESS) {
4c7f058cdd19ce67b2b5d4b7f69703d0f8a21e38Christian Maeder /* handle unexpected case where mapping for key already exists */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski if (val.i == gpo_map_type) {
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maeder /* mapping for key exists for same map type; no error */
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maeder DEBUG(SSSDBG_TRACE_FUNC,
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maeder "PAM service %s maps to %s multiple times\n", key.str,
9192fdd8f0e682ac0f0183dd854d5210fbfa4ec5Christian Maeder gpo_map_type_string(gpo_map_type));
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski ret = EOK;
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maeder } else {
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder /* mapping for key exists for different map type; error! */
0d0047d6eb457b56ff10987569769a420754a56fChristian Maeder DEBUG(SSSDBG_CRIT_FAILURE,
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maeder "PAM service %s maps to both %s and %s\n", key.str,
9192fdd8f0e682ac0f0183dd854d5210fbfa4ec5Christian Maeder gpo_map_type_string(val.i), gpo_map_type_string(gpo_map_type));
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maeder ret = EINVAL;
9192fdd8f0e682ac0f0183dd854d5210fbfa4ec5Christian Maeder }
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder goto done;
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder } else {
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder /* handle expected case where mapping for key doesn't already exist */
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder val.type = HASH_VALUE_INT;
e379124f467e5d0ef7d3c0ca238bff0521f70831Till Mossakowski val.i = gpo_map_type;
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder
24f14a27a838087b661c2e66fdec4e436ddbd832Christian Maeder hret = hash_enter(options_table, &key, &val);
24f14a27a838087b661c2e66fdec4e436ddbd832Christian Maeder if (hret != HASH_SUCCESS) {
24f14a27a838087b661c2e66fdec4e436ddbd832Christian Maeder DEBUG(SSSDBG_OP_FAILURE, "Error checking hash table: [%s]\n",
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder hash_error_string(hret));
6b00a9239fe7c804524099ca3d25f4ffc6079ceeChristian Maeder ret = EIO;
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder goto done;
b9804822fb178b0fc27ce967a6a8cedc42c5bf90Christian Maeder }
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder ret = EOK;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder }
b9804822fb178b0fc27ce967a6a8cedc42c5bf90Christian Maeder
283fdbf051a1cbcfe003ffdcb434564495106f13Christian Maederdone:
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder return ret;
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder}
283fdbf051a1cbcfe003ffdcb434564495106f13Christian Maeder
283fdbf051a1cbcfe003ffdcb434564495106f13Christian Maedererrno_t
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maederad_gpo_parse_map_option(TALLOC_CTX *mem_ctx,
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder enum gpo_map_type gpo_map_type,
283fdbf051a1cbcfe003ffdcb434564495106f13Christian Maeder hash_table_t *options_table,
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder char *conf_str,
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder const char **defaults)
c0380b947eef252db81ee562246bb732555427f4Till Mossakowski{
5b68f1141555736e0b7ddbe14218bcabcc44636fChristian Maeder TALLOC_CTX *tmp_ctx;
e24d81c69aecd41abb2f4969519c9e7126b1d687Christian Maeder errno_t ret;
27c2593d35d1013f630271ca2d1b566307aa4fb4Christian Maeder char **conf_list = NULL;
2afae0880da7ca73c9376fd4d653ab19833fe858Christian Maeder int conf_list_size = 0;
5b68f1141555736e0b7ddbe14218bcabcc44636fChristian Maeder char **add_list = NULL;
b9804822fb178b0fc27ce967a6a8cedc42c5bf90Christian Maeder char **remove_list = NULL;
9dfa1c020a030abdbcfce17b18000cc4e1f28462Christian Maeder int ai = 0, ri = 0;
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder int i;
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder hash_key_t key;
1bc5dccbf0083a620ae1181c717fea75e4af5e5cChristian Maeder
1bc5dccbf0083a620ae1181c717fea75e4af5e5cChristian Maeder tmp_ctx = talloc_new(NULL);
1bc5dccbf0083a620ae1181c717fea75e4af5e5cChristian Maeder if (tmp_ctx == NULL) {
4c7f058cdd19ce67b2b5d4b7f69703d0f8a21e38Christian Maeder ret = ENOMEM;
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder goto done;
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski }
4c7f058cdd19ce67b2b5d4b7f69703d0f8a21e38Christian Maeder
c0380b947eef252db81ee562246bb732555427f4Till Mossakowski DEBUG(SSSDBG_TRACE_ALL, "gpo_map_type: %s\n",
12368e292c1abf7eaf975f20ee30ef7820ac5dd5Christian Maeder gpo_map_type_string(gpo_map_type));
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder if (conf_str) {
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder ret = split_on_separator(tmp_ctx, conf_str, ',', true, true,
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder &conf_list, &conf_list_size);
9dfa1c020a030abdbcfce17b18000cc4e1f28462Christian Maeder if (ret != EOK) {
9dfa1c020a030abdbcfce17b18000cc4e1f28462Christian Maeder DEBUG(SSSDBG_OP_FAILURE,
0d0047d6eb457b56ff10987569769a420754a56fChristian Maeder "Cannot parse list of service names %s: %d\n", conf_str, ret);
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maeder ret = EINVAL;
c0380b947eef252db81ee562246bb732555427f4Till Mossakowski goto done;
c0380b947eef252db81ee562246bb732555427f4Till Mossakowski }
a05cad7f2f387b795a71a3aaec543c78e1b89d38Christian Maeder
37d0b201b8ba5d6056691e3055dd803e7928e163Christian Maeder add_list = talloc_zero_array(tmp_ctx, char *, conf_list_size);
9192fdd8f0e682ac0f0183dd854d5210fbfa4ec5Christian Maeder remove_list = talloc_zero_array(tmp_ctx, char *, conf_list_size);
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder if (add_list == NULL || remove_list == NULL) {
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder ret = ENOMEM;
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder goto done;
9d34a8049237647d0188ee2ec88db2dc45f1f848Till Mossakowski }
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder }
27c2593d35d1013f630271ca2d1b566307aa4fb4Christian Maeder
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder for (i = 0; i < conf_list_size; i++) {
cc4537e2e13b93e08fc8391d3abb8e412cb71b80Christian Maeder switch (conf_list[i][0]) {
cc4537e2e13b93e08fc8391d3abb8e412cb71b80Christian Maeder case '+':
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder add_list[ai] = conf_list[i] + 1;
9192fdd8f0e682ac0f0183dd854d5210fbfa4ec5Christian Maeder ai++;
278af20bd154d99e884bdf8c66d35d36699643c9Christian Maeder continue;
412aa5e819f3cd18f0be10b5571661036515b151Christian Maeder case '-':
7d5f239f3f1c1397e5d80caea12929bdf8abe2d8Christian Maeder remove_list[ri] = conf_list[i] + 1;
7d5f239f3f1c1397e5d80caea12929bdf8abe2d8Christian Maeder ri++;
7d5f239f3f1c1397e5d80caea12929bdf8abe2d8Christian Maeder continue;
7d5f239f3f1c1397e5d80caea12929bdf8abe2d8Christian Maeder default:
7d5f239f3f1c1397e5d80caea12929bdf8abe2d8Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "ad_gpo_map values must start with"
7d5f239f3f1c1397e5d80caea12929bdf8abe2d8Christian Maeder "either '+' (for adding service) or '-' (for removing service), "
283fdbf051a1cbcfe003ffdcb434564495106f13Christian Maeder "got '%s'\n",
a4cb1786d23060c8521a88f08f9909589fa83a12Christian Maeder conf_list[i]);
283fdbf051a1cbcfe003ffdcb434564495106f13Christian Maeder ret = EINVAL;
e379124f467e5d0ef7d3c0ca238bff0521f70831Till Mossakowski goto done;
63fb549acb4eddfd045bb55da66c1fd4ff5b1ac5Christian Maeder }
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder }
0d0047d6eb457b56ff10987569769a420754a56fChristian Maeder
7d5f239f3f1c1397e5d80caea12929bdf8abe2d8Christian Maeder /* Start by adding explicitly added services ('+') to hashtable */
7d5f239f3f1c1397e5d80caea12929bdf8abe2d8Christian Maeder for (i = 0; i < ai; i++) {
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder /* if the service is explicitly configured to be removed, skip it */
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder if (ad_gpo_service_in_list(remove_list, ri, add_list[i])) {
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder continue;
ef2affdc0cdf3acd5c051597c04ab9b08a346a7dChristian Maeder }
7d5f239f3f1c1397e5d80caea12929bdf8abe2d8Christian Maeder
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder key.type = HASH_KEY_STRING;
412aa5e819f3cd18f0be10b5571661036515b151Christian Maeder key.str = (char *)add_list[i];
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder
412aa5e819f3cd18f0be10b5571661036515b151Christian Maeder ret = ad_gpo_parse_map_option_helper(gpo_map_type, key, options_table);
278af20bd154d99e884bdf8c66d35d36699643c9Christian Maeder if (ret != EOK) {
412aa5e819f3cd18f0be10b5571661036515b151Christian Maeder DEBUG(SSSDBG_OP_FAILURE, "Invalid configuration: %d\n", ret);
412aa5e819f3cd18f0be10b5571661036515b151Christian Maeder goto done;
412aa5e819f3cd18f0be10b5571661036515b151Christian Maeder }
412aa5e819f3cd18f0be10b5571661036515b151Christian Maeder
412aa5e819f3cd18f0be10b5571661036515b151Christian Maeder DEBUG(SSSDBG_TRACE_ALL, "Explicitly added service: %s\n", key.str);
412aa5e819f3cd18f0be10b5571661036515b151Christian Maeder }
cc4537e2e13b93e08fc8391d3abb8e412cb71b80Christian Maeder
cc4537e2e13b93e08fc8391d3abb8e412cb71b80Christian Maeder /* Add defaults to hashtable */
c5653d37b37dcc025ff6dd1eada95ae67116e699Christian Maeder for (i = 0; defaults[i]; i++) {
cc4537e2e13b93e08fc8391d3abb8e412cb71b80Christian Maeder /* if the service is explicitly configured to be removed, skip it */
13d0d9a3df7f3998f3c18c2fccbf2e3bbacbd4b5Christian Maeder if (ad_gpo_service_in_list(remove_list, ri, defaults[i])) {
278af20bd154d99e884bdf8c66d35d36699643c9Christian Maeder continue;
412aa5e819f3cd18f0be10b5571661036515b151Christian Maeder }
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski
7d5f239f3f1c1397e5d80caea12929bdf8abe2d8Christian Maeder key.type = HASH_KEY_STRING;
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder key.str = talloc_strdup(mem_ctx, defaults[i]);
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder ret = ad_gpo_parse_map_option_helper(gpo_map_type, key, options_table);
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder if (ret != EOK) {
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder DEBUG(SSSDBG_OP_FAILURE, "Invalid configuration: %d\n", ret);
083a5256468076d5a9bfeb22a6e97076c224252eChristian Maeder goto done;
06afcb70f335c6de74007dc5d6bb19a7d06de457Christian Maeder }
06afcb70f335c6de74007dc5d6bb19a7d06de457Christian Maeder
06afcb70f335c6de74007dc5d6bb19a7d06de457Christian Maeder DEBUG(SSSDBG_TRACE_ALL, "Default service (not explicitly removed): %s\n",
13d0d9a3df7f3998f3c18c2fccbf2e3bbacbd4b5Christian Maeder key.str);
278af20bd154d99e884bdf8c66d35d36699643c9Christian Maeder }
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder ret = EOK;
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maederdone:
d210b655b5f93a0fff2eefbb94c072d450cef3b4Till Mossakowski talloc_free(tmp_ctx);
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder return ret;
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder}
7d5f239f3f1c1397e5d80caea12929bdf8abe2d8Christian Maeder
7d5f239f3f1c1397e5d80caea12929bdf8abe2d8Christian Maedererrno_t
ba5c87b3f4a921f0932a08de48a3aedd3ca4d25bTill Mossakowskiad_gpo_parse_map_options(struct ad_access_ctx *access_ctx)
ba5c87b3f4a921f0932a08de48a3aedd3ca4d25bTill Mossakowski{
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder char *gpo_default_right_config;
7d5f239f3f1c1397e5d80caea12929bdf8abe2d8Christian Maeder enum gpo_map_type gpo_default_right;
e3c9174a782e90f965a0b080c22861c3ef5af12dTill Mossakowski errno_t ret;
ba5c87b3f4a921f0932a08de48a3aedd3ca4d25bTill Mossakowski int i;
ba5c87b3f4a921f0932a08de48a3aedd3ca4d25bTill Mossakowski
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder for (i = 0; i < GPO_MAP_NUM_OPTS; i++) {
b3dca469a9e267d6d71acfdeca7bf284d0581dc7Till Mossakowski
b3dca469a9e267d6d71acfdeca7bf284d0581dc7Till Mossakowski struct gpo_map_option_entry entry = gpo_map_option_entries[i];
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder
ba5c87b3f4a921f0932a08de48a3aedd3ca4d25bTill Mossakowski char *entry_config = dp_opt_get_string(access_ctx->ad_options,
be3f5e3e69900ececafea5b010a8400f26af5362Christian Maeder entry.ad_basic_opt);
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder
ba5c87b3f4a921f0932a08de48a3aedd3ca4d25bTill Mossakowski ret = ad_gpo_parse_map_option(access_ctx, entry.gpo_map_type,
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder access_ctx->gpo_map_options_table,
ba5c87b3f4a921f0932a08de48a3aedd3ca4d25bTill Mossakowski entry_config, entry.gpo_map_defaults);
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder
ba5c87b3f4a921f0932a08de48a3aedd3ca4d25bTill Mossakowski if (ret != EOK) {
c40822a6238ef14ebd3df830204c2790a68c8076Christian Maeder DEBUG(SSSDBG_OP_FAILURE, "Invalid configuration: %d\n", ret);
12368e292c1abf7eaf975f20ee30ef7820ac5dd5Christian Maeder ret = EINVAL;
12368e292c1abf7eaf975f20ee30ef7820ac5dd5Christian Maeder goto fail;
4c7f058cdd19ce67b2b5d4b7f69703d0f8a21e38Christian Maeder }
9192fdd8f0e682ac0f0183dd854d5210fbfa4ec5Christian Maeder }
ba5c87b3f4a921f0932a08de48a3aedd3ca4d25bTill Mossakowski
c30cfe2a6ab063befdfb47449bc286caee6d8fc3Christian Maeder /* default right (applicable for services without any mapping) */
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder gpo_default_right_config =
b3dca469a9e267d6d71acfdeca7bf284d0581dc7Till Mossakowski dp_opt_get_string(access_ctx->ad_options, AD_GPO_DEFAULT_RIGHT);
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder DEBUG(SSSDBG_TRACE_ALL, "gpo_default_right_config: %s\n",
0d0047d6eb457b56ff10987569769a420754a56fChristian Maeder gpo_default_right_config);
5b1394673f35f4d23cfe08175841ab414a39678eMarkus Roggenbach
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder /* if default right not set in config, set them to DENY */
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder if (gpo_default_right_config == NULL) {
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder gpo_default_right = GPO_MAP_DENY;
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder } else if (strncasecmp(gpo_default_right_config, "interactive",
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder strlen("interactive")) == 0) {
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder gpo_default_right = GPO_MAP_INTERACTIVE;
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder } else if (strncasecmp(gpo_default_right_config, "remote_interactive",
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder strlen("remote_interactive")) == 0) {
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder gpo_default_right = GPO_MAP_REMOTE_INTERACTIVE;
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder } else if (strncasecmp(gpo_default_right_config, "network",
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder strlen("network")) == 0) {
c5bc8d60f7c753f81746828329d9e92db1ab7abaChristian Maeder gpo_default_right = GPO_MAP_NETWORK;
22250d2b3c9f86fe19cba665d71c301de03db142Christian Maeder } else if (strncasecmp(gpo_default_right_config, "batch",
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder strlen("batch")) == 0) {
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder gpo_default_right = GPO_MAP_BATCH;
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder } else if (strncasecmp(gpo_default_right_config, "service",
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder strlen("service")) == 0) {
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder gpo_default_right = GPO_MAP_SERVICE;
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder } else if (strncasecmp(gpo_default_right_config, "permit",
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder strlen("permit")) == 0) {
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder gpo_default_right = GPO_MAP_PERMIT;
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder } else if (strncasecmp(gpo_default_right_config, "deny",
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder strlen("deny")) == 0) {
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder gpo_default_right = GPO_MAP_DENY;
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder } else {
5a87ed846cc38cb0e3adf8f736d95614d3e724a3Christian Maeder ret = EINVAL;
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder goto fail;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder }
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder DEBUG(SSSDBG_TRACE_ALL, "gpo_default_right: %d\n", gpo_default_right);
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder access_ctx->gpo_default_right = gpo_default_right;
1805f9816e3414ab184fb8546ab1abc6241f04cdChristian Maeder
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maederfail:
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder return ret;
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder}
2701083ab584807a8dec6f2c8bc03237a25d9809Christian Maeder
2701083ab584807a8dec6f2c8bc03237a25d9809Christian Maeder/* == ad_gpo_access_send/recv helpers =======================================*/
ecf557c0b4f953106755a239da2c0b168064d3f4Christian Maeder
1805f9816e3414ab184fb8546ab1abc6241f04cdChristian Maederstatic bool
1805f9816e3414ab184fb8546ab1abc6241f04cdChristian Maederad_gpo_dom_sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2)
1805f9816e3414ab184fb8546ab1abc6241f04cdChristian Maeder{
1805f9816e3414ab184fb8546ab1abc6241f04cdChristian Maeder int i;
ecf557c0b4f953106755a239da2c0b168064d3f4Christian Maeder
1805f9816e3414ab184fb8546ab1abc6241f04cdChristian Maeder if (sid1 == sid2) {
9efe0bf51725355f7a8be26dd44bb6a69212e7beChristian Maeder return true;
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder }
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder
1805f9816e3414ab184fb8546ab1abc6241f04cdChristian Maeder if (!sid1 || !sid2) {
1805f9816e3414ab184fb8546ab1abc6241f04cdChristian Maeder return false;
1805f9816e3414ab184fb8546ab1abc6241f04cdChristian Maeder }
1805f9816e3414ab184fb8546ab1abc6241f04cdChristian Maeder
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder if (sid1->sid_rev_num != sid2->sid_rev_num) {
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder return false;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder }
ecf557c0b4f953106755a239da2c0b168064d3f4Christian Maeder
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder for (i = 0; i < 6; i++) {
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder if (sid1->id_auth[i] != sid2->id_auth[i]) {
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder return false;
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder }
2701083ab584807a8dec6f2c8bc03237a25d9809Christian Maeder }
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder
2701083ab584807a8dec6f2c8bc03237a25d9809Christian Maeder if (sid1->num_auths != sid2->num_auths) {
627ed7abdbae641636a2d0f2510c0d450f5ee915Christian Maeder return false;
2701083ab584807a8dec6f2c8bc03237a25d9809Christian Maeder }
2701083ab584807a8dec6f2c8bc03237a25d9809Christian Maeder
2701083ab584807a8dec6f2c8bc03237a25d9809Christian Maeder for (i = 0; i < sid1->num_auths; i++) {
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder if (sid1->sub_auths[i] != sid2->sub_auths[i]) {
2701083ab584807a8dec6f2c8bc03237a25d9809Christian Maeder return false;
52aad0502f0ddd332a28ae3fcd3327fa66d002f7Till Mossakowski }
52aad0502f0ddd332a28ae3fcd3327fa66d002f7Till Mossakowski }
52aad0502f0ddd332a28ae3fcd3327fa66d002f7Till Mossakowski
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder return true;
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder}
52aad0502f0ddd332a28ae3fcd3327fa66d002f7Till Mossakowski
52aad0502f0ddd332a28ae3fcd3327fa66d002f7Till Mossakowski
52aad0502f0ddd332a28ae3fcd3327fa66d002f7Till Mossakowski/*
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder * This function retrieves the SIDs corresponding to the input user and returns
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder * the user_sid, group_sids, and group_size in their respective output params.
52aad0502f0ddd332a28ae3fcd3327fa66d002f7Till Mossakowski *
52aad0502f0ddd332a28ae3fcd3327fa66d002f7Till Mossakowski * Note: since authentication must complete successfully before the
52aad0502f0ddd332a28ae3fcd3327fa66d002f7Till Mossakowski * gpo access checks are called, we can safely assume that the user/computer
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder * has been authenticated. As such, this function always adds the
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder * AD_AUTHENTICATED_USERS_SID to the group_sids.
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder */
52aad0502f0ddd332a28ae3fcd3327fa66d002f7Till Mossakowskistatic errno_t
2701083ab584807a8dec6f2c8bc03237a25d9809Christian Maederad_gpo_get_sids(TALLOC_CTX *mem_ctx,
2701083ab584807a8dec6f2c8bc03237a25d9809Christian Maeder const char *user,
52aad0502f0ddd332a28ae3fcd3327fa66d002f7Till Mossakowski struct sss_domain_info *domain,
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder const char **_user_sid,
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder const char ***_group_sids,
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder int *_group_size)
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder{
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder TALLOC_CTX *tmp_ctx = NULL;
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder struct ldb_result *res;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder int ret = 0;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder int i = 0;
de66af0f4b27f08f81c7ca9c573ef9cdf7ca7a07Christian Maeder int num_group_sids = 0;
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder const char *user_sid = NULL;
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder const char *group_sid = NULL;
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder const char **group_sids = NULL;
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder tmp_ctx = talloc_new(NULL);
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder if (tmp_ctx == NULL) {
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder ret = ENOMEM;
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder goto done;
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder }
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder /* first result from sysdb_initgroups is user_sid; rest are group_sids */
62607bfd8541a700d18aee4f9cdb037aded5ab0bChristian Maeder ret = sysdb_initgroups(tmp_ctx, domain, user, &res);
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder if (ret != EOK) {
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder DEBUG(SSSDBG_OP_FAILURE,
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder "sysdb_initgroups failed: [%d](%s)\n",
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder ret, sss_strerror(ret));
1bc5dccbf0083a620ae1181c717fea75e4af5e5cChristian Maeder return ret;
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder }
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder if (res->count == 0) {
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder ret = ENOENT;
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder DEBUG(SSSDBG_OP_FAILURE,
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder "sysdb_initgroups returned empty result\n");
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder return ret;
4c7f058cdd19ce67b2b5d4b7f69703d0f8a21e38Christian Maeder }
4c7f058cdd19ce67b2b5d4b7f69703d0f8a21e38Christian Maeder
de66af0f4b27f08f81c7ca9c573ef9cdf7ca7a07Christian Maeder user_sid = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SID_STR, NULL);
de66af0f4b27f08f81c7ca9c573ef9cdf7ca7a07Christian Maeder num_group_sids = (res->count) - 1;
12368e292c1abf7eaf975f20ee30ef7820ac5dd5Christian Maeder
12368e292c1abf7eaf975f20ee30ef7820ac5dd5Christian Maeder /* include space for AD_AUTHENTICATED_USERS_SID and NULL */
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder group_sids = talloc_array(tmp_ctx, const char *, num_group_sids + 1 + 1);
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder if (group_sids == NULL) {
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder ret = ENOMEM;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder goto done;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder }
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder
37d0b201b8ba5d6056691e3055dd803e7928e163Christian Maeder for (i = 0; i < num_group_sids; i++) {
4c7f058cdd19ce67b2b5d4b7f69703d0f8a21e38Christian Maeder group_sid = ldb_msg_find_attr_as_string(res->msgs[i+1],
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder SYSDB_SID_STR, NULL);
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder if (group_sid == NULL) {
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder continue;
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder }
ecf557c0b4f953106755a239da2c0b168064d3f4Christian Maeder
1bc5dccbf0083a620ae1181c717fea75e4af5e5cChristian Maeder group_sids[i] = talloc_steal(group_sids, group_sid);
1bc5dccbf0083a620ae1181c717fea75e4af5e5cChristian Maeder if (group_sids[i] == NULL) {
ecf557c0b4f953106755a239da2c0b168064d3f4Christian Maeder ret = ENOMEM;
ecf557c0b4f953106755a239da2c0b168064d3f4Christian Maeder goto done;
7bf4436b6f9987b070033a323757b206c898c1beChristian Maeder }
ecf557c0b4f953106755a239da2c0b168064d3f4Christian Maeder }
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder group_sids[i++] = talloc_strdup(group_sids, AD_AUTHENTICATED_USERS_SID);
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski group_sids[i] = NULL;
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder *_group_size = num_group_sids + 1;
79ee6b8eb396ed31807784a4bb1c9cc2ce094835Till Mossakowski *_group_sids = talloc_steal(mem_ctx, group_sids);
79ee6b8eb396ed31807784a4bb1c9cc2ce094835Till Mossakowski *_user_sid = talloc_steal(mem_ctx, user_sid);
ecf557c0b4f953106755a239da2c0b168064d3f4Christian Maeder return EOK;
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder done:
ecf557c0b4f953106755a239da2c0b168064d3f4Christian Maeder talloc_free(tmp_ctx);
ecf557c0b4f953106755a239da2c0b168064d3f4Christian Maeder return ret;
37d0b201b8ba5d6056691e3055dd803e7928e163Christian Maeder}
37d0b201b8ba5d6056691e3055dd803e7928e163Christian Maeder
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder/*
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder * This function determines whether the input ace_dom_sid matches any of the
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder * client's SIDs. The boolean result is assigned to the _included output param.
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder */
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maederstatic errno_t
f8fe1f095d5b7fd96bde0784289b001446e60d0bChristian Maederad_gpo_ace_includes_client_sid(const char *user_sid,
f8fe1f095d5b7fd96bde0784289b001446e60d0bChristian Maeder const char **group_sids,
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder int group_size,
f8fe1f095d5b7fd96bde0784289b001446e60d0bChristian Maeder struct dom_sid ace_dom_sid,
f8fe1f095d5b7fd96bde0784289b001446e60d0bChristian Maeder struct sss_idmap_ctx *idmap_ctx,
f8fe1f095d5b7fd96bde0784289b001446e60d0bChristian Maeder bool *_included)
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder{
f8fe1f095d5b7fd96bde0784289b001446e60d0bChristian Maeder int i = 0;
f8fe1f095d5b7fd96bde0784289b001446e60d0bChristian Maeder struct dom_sid *user_dom_sid;
ecf557c0b4f953106755a239da2c0b168064d3f4Christian Maeder struct dom_sid *group_dom_sid;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder enum idmap_error_code err;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder bool included = false;
083a5256468076d5a9bfeb22a6e97076c224252eChristian Maeder
083a5256468076d5a9bfeb22a6e97076c224252eChristian Maeder err = sss_idmap_sid_to_smb_sid(idmap_ctx, user_sid, &user_dom_sid);
083a5256468076d5a9bfeb22a6e97076c224252eChristian Maeder if (err != IDMAP_SUCCESS) {
a89e661aad28f1b39f4fc9f9f9a4d46074234123Christian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize idmap context.\n");
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder return EFAULT;
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder }
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder
a89e661aad28f1b39f4fc9f9f9a4d46074234123Christian Maeder included = ad_gpo_dom_sid_equal(&ace_dom_sid, user_dom_sid);
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder sss_idmap_free_smb_sid(idmap_ctx, user_dom_sid);
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder if (included) {
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder *_included = true;
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder return EOK;
f8fe1f095d5b7fd96bde0784289b001446e60d0bChristian Maeder }
c5653d37b37dcc025ff6dd1eada95ae67116e699Christian Maeder
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder for (i = 0; i < group_size; i++) {
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder err = sss_idmap_sid_to_smb_sid(idmap_ctx, group_sids[i], &group_dom_sid);
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder if (err != IDMAP_SUCCESS) {
f8fe1f095d5b7fd96bde0784289b001446e60d0bChristian Maeder DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize idmap context.\n");
f8fe1f095d5b7fd96bde0784289b001446e60d0bChristian Maeder return EFAULT;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder }
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder included = ad_gpo_dom_sid_equal(&ace_dom_sid, group_dom_sid);
c528d35d975276f43d31dec4db9b4e1bf08e1fe2Christian Maeder sss_idmap_free_smb_sid(idmap_ctx, group_dom_sid);
c528d35d975276f43d31dec4db9b4e1bf08e1fe2Christian Maeder if (included) {
c528d35d975276f43d31dec4db9b4e1bf08e1fe2Christian Maeder *_included = true;
c528d35d975276f43d31dec4db9b4e1bf08e1fe2Christian Maeder return EOK;
c528d35d975276f43d31dec4db9b4e1bf08e1fe2Christian Maeder }
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder }
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder
691ca0c9c7b21d58170be61c9c58899c5594fb2fChristian Maeder *_included = false;
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder return EOK;
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder}
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder/*
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder * This function determines whether use of the extended right
8ecf5884934cad4efbcd60b92671b74e4aaeb62bChristian Maeder * named "ApplyGroupPolicy" (AGP) is allowed, by comparing the specified
8ecf5884934cad4efbcd60b92671b74e4aaeb62bChristian Maeder * user_sid and group_sids against the specified access control entry (ACE).
1b2649da700cc49d0d49e463e3962c07770f6204Christian Maeder * This function returns ALLOWED, DENIED, or NEUTRAL depending on whether
1b2649da700cc49d0d49e463e3962c07770f6204Christian Maeder * the ACE explictly allows, explicitly denies, or does neither.
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder *
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder * Note that the 'M' abbreviation used in the evaluation algorithm stands for
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder * "access_mask", which represents the set of access rights associated with an
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder * individual ACE. The access right of interest to the GPO code is
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder * RIGHT_DS_CONTROL_ACCESS, which serves as a container for all control access
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder * rights. The specific control access right is identified by a GUID in the
8ecf5884934cad4efbcd60b92671b74e4aaeb62bChristian Maeder * ACE's ObjectType. In our case, this is the GUID corresponding to AGP.
8ecf5884934cad4efbcd60b92671b74e4aaeb62bChristian Maeder *
8ecf5884934cad4efbcd60b92671b74e4aaeb62bChristian Maeder * The ACE evaluation algorithm is specified in [MS-ADTS] 5.1.3.3.4:
8ecf5884934cad4efbcd60b92671b74e4aaeb62bChristian Maeder * - Deny access by default
8ecf5884934cad4efbcd60b92671b74e4aaeb62bChristian Maeder * - If the "Inherit Only" (IO) flag is set in the ACE, skip the ACE.
8ecf5884934cad4efbcd60b92671b74e4aaeb62bChristian Maeder * - If the SID in the ACE does not match any SID in the requester's
c5653d37b37dcc025ff6dd1eada95ae67116e699Christian Maeder * security context, skip the ACE
8ecf5884934cad4efbcd60b92671b74e4aaeb62bChristian Maeder * - If the ACE type is "Object Access Allowed", the access right
c5653d37b37dcc025ff6dd1eada95ae67116e699Christian Maeder * RIGHT_DS_CONTROL_ACCESS (CR) is present in M, and the ObjectType
13d0d9a3df7f3998f3c18c2fccbf2e3bbacbd4b5Christian Maeder * field in the ACE is either not present OR contains a GUID value equal
13d0d9a3df7f3998f3c18c2fccbf2e3bbacbd4b5Christian Maeder * to AGP, then grant requested control access right. Stop access checking.
8ecf5884934cad4efbcd60b92671b74e4aaeb62bChristian Maeder * - If the ACE type is "Object Access Denied", the access right
c5653d37b37dcc025ff6dd1eada95ae67116e699Christian Maeder * RIGHT_DS_CONTROL_ACCESS (CR) is present in M, and the ObjectType
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder * field in the ACE is either not present OR contains a GUID value equal to
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder * AGP, then deny the requested control access right. Stop access checking.
083a5256468076d5a9bfeb22a6e97076c224252eChristian Maeder */
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maederstatic enum ace_eval_status ad_gpo_evaluate_ace(struct security_ace *ace,
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder struct sss_idmap_ctx *idmap_ctx,
691ca0c9c7b21d58170be61c9c58899c5594fb2fChristian Maeder const char *user_sid,
691ca0c9c7b21d58170be61c9c58899c5594fb2fChristian Maeder const char **group_sids,
c5653d37b37dcc025ff6dd1eada95ae67116e699Christian Maeder int group_size)
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder{
691ca0c9c7b21d58170be61c9c58899c5594fb2fChristian Maeder bool agp_included = false;
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder bool included = false;
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder int ret = 0;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder struct security_ace_object object;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder struct GUID ext_right_agp_guid;
13d0d9a3df7f3998f3c18c2fccbf2e3bbacbd4b5Christian Maeder
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder return AD_GPO_ACE_NEUTRAL;
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder }
c5653d37b37dcc025ff6dd1eada95ae67116e699Christian Maeder
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder ret = ad_gpo_ace_includes_client_sid(user_sid, group_sids, group_size,
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder ace->trustee, idmap_ctx, &included);
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder
cdcca7a63a02d363730ee1060e2500343da76afaChristian Maeder if (ret != EOK) {
cdcca7a63a02d363730ee1060e2500343da76afaChristian Maeder return AD_GPO_ACE_DENIED;
cdcca7a63a02d363730ee1060e2500343da76afaChristian Maeder }
cdcca7a63a02d363730ee1060e2500343da76afaChristian Maeder
cdcca7a63a02d363730ee1060e2500343da76afaChristian Maeder if (!included) {
cdcca7a63a02d363730ee1060e2500343da76afaChristian Maeder return AD_GPO_ACE_NEUTRAL;
cdcca7a63a02d363730ee1060e2500343da76afaChristian Maeder }
cdcca7a63a02d363730ee1060e2500343da76afaChristian Maeder
cdcca7a63a02d363730ee1060e2500343da76afaChristian Maeder object = ace->object.object;
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder GUID_from_string(AD_AGP_GUID, &ext_right_agp_guid);
c5653d37b37dcc025ff6dd1eada95ae67116e699Christian Maeder
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder if (object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder if (GUID_equal(&object.type.type, &ext_right_agp_guid)) {
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder agp_included = true;
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder }
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder } else {
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder agp_included = false;
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder }
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder if (ace->access_mask & SEC_ADS_CONTROL_ACCESS) {
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder if (agp_included) {
c5653d37b37dcc025ff6dd1eada95ae67116e699Christian Maeder if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT) {
1d10e9a6a3b03c7aa4306ff936ccaeacf474059aChristian Maeder return AD_GPO_ACE_ALLOWED;
1d10e9a6a3b03c7aa4306ff936ccaeacf474059aChristian Maeder } else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT) {
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder return AD_GPO_ACE_DENIED;
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder }
3d774b4dfa0e459c1a3b08b4aa32c85aa4875362Christian Maeder }
1d10e9a6a3b03c7aa4306ff936ccaeacf474059aChristian Maeder }
1d10e9a6a3b03c7aa4306ff936ccaeacf474059aChristian Maeder
1d10e9a6a3b03c7aa4306ff936ccaeacf474059aChristian Maeder return AD_GPO_ACE_DENIED;
1d10e9a6a3b03c7aa4306ff936ccaeacf474059aChristian Maeder}
1d10e9a6a3b03c7aa4306ff936ccaeacf474059aChristian Maeder
1d10e9a6a3b03c7aa4306ff936ccaeacf474059aChristian Maeder/*
1d10e9a6a3b03c7aa4306ff936ccaeacf474059aChristian Maeder * This function extracts the GPO's DACL (discretionary access control list)
1d10e9a6a3b03c7aa4306ff936ccaeacf474059aChristian Maeder * from the GPO's specified security descriptor, and determines whether
1d10e9a6a3b03c7aa4306ff936ccaeacf474059aChristian Maeder * the GPO is applicable to the policy target, by comparing the specified
cdcca7a63a02d363730ee1060e2500343da76afaChristian Maeder * user_sid and group_sids against each access control entry (ACE) in the DACL.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * The boolean result is assigned to the _access_allowed output parameter.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskistatic errno_t ad_gpo_evaluate_dacl(struct security_acl *dacl,
3476beb5baf84bef7cc7d627b130de9d48700399Christian Maeder struct sss_idmap_ctx *idmap_ctx,
3476beb5baf84bef7cc7d627b130de9d48700399Christian Maeder const char *user_sid,
3476beb5baf84bef7cc7d627b130de9d48700399Christian Maeder const char **group_sids,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski int group_size,
0dcb86310998e097d3b15608f980f0a89a11a322Christian Maeder bool *_dacl_access_allowed)
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski{
dbbcdfeafa68c87e0b2be0096788844e2be08345Christian Maeder uint32_t num_aces = 0;
410ff490af511ffa09b52e4de631d36a154b9730Christian Maeder enum ace_eval_status ace_status;
410ff490af511ffa09b52e4de631d36a154b9730Christian Maeder int i = 0;
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder struct security_ace *ace = NULL;
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder num_aces = dacl->num_aces;
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder /*
88ece6e49930670e8fd3ee79c89a2e918d2fbd0cChristian Maeder * [MS-ADTS] 5.1.3.3.4:
3476beb5baf84bef7cc7d627b130de9d48700399Christian Maeder * If the DACL does not have any ACE, then deny the requester the
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * requested control access right.
0dcb86310998e097d3b15608f980f0a89a11a322Christian Maeder */
0dcb86310998e097d3b15608f980f0a89a11a322Christian Maeder if (num_aces == 0) {
0dcb86310998e097d3b15608f980f0a89a11a322Christian Maeder *_dacl_access_allowed = false;
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski return EOK;
88ece6e49930670e8fd3ee79c89a2e918d2fbd0cChristian Maeder }
3476beb5baf84bef7cc7d627b130de9d48700399Christian Maeder
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski for (i = 0; i < dacl->num_aces; i ++) {
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder ace = &dacl->aces[i];
7297175957c5ad3c0498032190b1dee9ec5fb873Christian Maeder
7297175957c5ad3c0498032190b1dee9ec5fb873Christian Maeder ace_status = ad_gpo_evaluate_ace(ace, idmap_ctx, user_sid,
7297175957c5ad3c0498032190b1dee9ec5fb873Christian Maeder group_sids, group_size);
64601796d2f62ffe61e9a5340dc569dd41dc2244Christian Maeder
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder switch (ace_status) {
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder case AD_GPO_ACE_NEUTRAL:
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder continue;
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder case AD_GPO_ACE_ALLOWED:
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder *_dacl_access_allowed = true;
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder return EOK;
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder case AD_GPO_ACE_DENIED:
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder *_dacl_access_allowed = false;
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder return EOK;
88ece6e49930670e8fd3ee79c89a2e918d2fbd0cChristian Maeder }
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski }
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder *_dacl_access_allowed = false;
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder return EOK;
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski}
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder/*
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder * This function takes candidate_gpos as input, filters out any gpo that is
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * not applicable to the policy target and assigns the result to the
3476beb5baf84bef7cc7d627b130de9d48700399Christian Maeder * _dacl_filtered_gpos output parameter. The filtering algorithm is
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder * defined in [MS-GPOL] 3.2.5.1.6
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder */
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maederstatic errno_t
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maederad_gpo_filter_gpos_by_dacl(TALLOC_CTX *mem_ctx,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski const char *user,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski struct sss_domain_info *domain,
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder struct sss_idmap_ctx *idmap_ctx,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski struct gp_gpo **candidate_gpos,
4c7f058cdd19ce67b2b5d4b7f69703d0f8a21e38Christian Maeder int num_candidate_gpos,
d8220f52119f85832e72228b82543fa638449eecChristian Maeder struct gp_gpo ***_dacl_filtered_gpos,
3cb09c6460a2262e392c759e363bf645f913a47aChristian Maeder int *_num_dacl_filtered_gpos)
1bc5dccbf0083a620ae1181c717fea75e4af5e5cChristian Maeder{
1bc5dccbf0083a620ae1181c717fea75e4af5e5cChristian Maeder TALLOC_CTX *tmp_ctx = NULL;
88ece6e49930670e8fd3ee79c89a2e918d2fbd0cChristian Maeder int i = 0;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder int ret = 0;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder struct gp_gpo *candidate_gpo = NULL;
89ab08979dc23d72e9e09c8990a8c44847041d6fChristian Maeder struct security_descriptor *sd = NULL;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder struct security_acl *dacl = NULL;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder const char *user_sid = NULL;
ed20c3b1e992d174a2cbb2077e61817527f8e061Christian Maeder const char **group_sids = NULL;
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder int group_size = 0;
f9690de9acb57e279b8ad5792d71b48ffbb807e7Christian Maeder int gpo_dn_idx = 0;
f9690de9acb57e279b8ad5792d71b48ffbb807e7Christian Maeder bool access_allowed = false;
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder struct gp_gpo **dacl_filtered_gpos = NULL;
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder
ed20c3b1e992d174a2cbb2077e61817527f8e061Christian Maeder tmp_ctx = talloc_new(NULL);
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder if (tmp_ctx == NULL) {
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder ret = ENOMEM;
6010f37233a15cb25960c86afaa4a23bbaa6a86cChristian Maeder goto done;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder }
1bc5dccbf0083a620ae1181c717fea75e4af5e5cChristian Maeder
4c7f058cdd19ce67b2b5d4b7f69703d0f8a21e38Christian Maeder ret = ad_gpo_get_sids(tmp_ctx, user, domain, &user_sid,
64601796d2f62ffe61e9a5340dc569dd41dc2244Christian Maeder &group_sids, &group_size);
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski if (ret != EOK) {
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder ret = ERR_NO_SIDS;
64601796d2f62ffe61e9a5340dc569dd41dc2244Christian Maeder DEBUG(SSSDBG_OP_FAILURE,
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder "Unable to retrieve SIDs: [%d](%s)\n", ret, sss_strerror(ret));
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder goto done;
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder }
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder dacl_filtered_gpos = talloc_array(tmp_ctx,
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder struct gp_gpo *,
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder num_candidate_gpos + 1);
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder if (dacl_filtered_gpos == NULL) {
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder ret = ENOMEM;
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder goto done;
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder }
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder
ef2affdc0cdf3acd5c051597c04ab9b08a346a7dChristian Maeder for (i = 0; i < num_candidate_gpos; i++) {
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder access_allowed = false;
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder candidate_gpo = candidate_gpos[i];
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder sd = candidate_gpo->gpo_sd;
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder dacl = candidate_gpo->gpo_sd->dacl;
95c27038582e8a2ce24923bee69ef15931b8b87bChristian Maeder
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder DEBUG(SSSDBG_TRACE_ALL, "examining dacl candidate_gpo_guid:%s\n",
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder candidate_gpo->gpo_guid);
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder /* gpo_func_version must be set to version 2 */
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder if (candidate_gpo->gpo_func_version != 2) {
587fb54160b66128cf17e4c9bca7494a7f2c3c4aChristian Maeder DEBUG(SSSDBG_TRACE_ALL,
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder "GPO not applicable to target per security filtering\n");
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder continue;
6157bf81d295795067c177aa870fedff83cbe750Christian Maeder }
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder
a80f2865b6b40a922bcccfce0cb0d047edc33e3aChristian Maeder /* gpo_flags value of 2 means that GPO's computer portion is disabled */
587fb54160b66128cf17e4c9bca7494a7f2c3c4aChristian Maeder if (candidate_gpo->gpo_flags == 2) {
22dd6d9af47163ee081d6c505d0a13dbf40ba87aChristian Maeder DEBUG(SSSDBG_TRACE_ALL,
7297175957c5ad3c0498032190b1dee9ec5fb873Christian Maeder "GPO not applicable to target per security filtering\n");
b03274844ecd270f9e9331f51cc4236a33e2e671Christian Maeder continue;
0d0047d6eb457b56ff10987569769a420754a56fChristian Maeder }
0d0047d6eb457b56ff10987569769a420754a56fChristian Maeder
95c3e5d11dcee331dc3876a9bf0c1d6daa38e2caChristian Maeder /*
4a8f990902448d0562fbe1a98ce685ddbd531d38Christian Maeder * [MS-ADTS] 5.1.3.3.4:
4a8f990902448d0562fbe1a98ce685ddbd531d38Christian Maeder * If the security descriptor has no DACL or its "DACL Present" bit
4a8f990902448d0562fbe1a98ce685ddbd531d38Christian Maeder * is not set, then grant requester the requested control access right.
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder */
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder
dbbcdfeafa68c87e0b2be0096788844e2be08345Christian Maeder if ((!(sd->type & SEC_DESC_DACL_PRESENT)) || (dacl == NULL)) {
dbbcdfeafa68c87e0b2be0096788844e2be08345Christian Maeder DEBUG(SSSDBG_TRACE_ALL, "DACL is not present\n");
dbbcdfeafa68c87e0b2be0096788844e2be08345Christian Maeder access_allowed = true;
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder break;
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder }
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder ret = ad_gpo_evaluate_dacl(dacl, idmap_ctx, user_sid, group_sids,
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder group_size, &access_allowed);
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder if (ret != EOK) {
4a8f990902448d0562fbe1a98ce685ddbd531d38Christian Maeder DEBUG(SSSDBG_MINOR_FAILURE, "Could not determine if GPO is applicable\n");
4a8f990902448d0562fbe1a98ce685ddbd531d38Christian Maeder continue;
4a8f990902448d0562fbe1a98ce685ddbd531d38Christian Maeder }
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder
6b00a9239fe7c804524099ca3d25f4ffc6079ceeChristian Maeder if (access_allowed) {
6b00a9239fe7c804524099ca3d25f4ffc6079ceeChristian Maeder DEBUG(SSSDBG_TRACE_ALL,
4a8f990902448d0562fbe1a98ce685ddbd531d38Christian Maeder "GPO applicable to target per security filtering\n");
6b00a9239fe7c804524099ca3d25f4ffc6079ceeChristian Maeder dacl_filtered_gpos[gpo_dn_idx] = talloc_steal(dacl_filtered_gpos,
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder candidate_gpo);
6b00a9239fe7c804524099ca3d25f4ffc6079ceeChristian Maeder gpo_dn_idx++;
4a8f990902448d0562fbe1a98ce685ddbd531d38Christian Maeder } else {
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder DEBUG(SSSDBG_TRACE_ALL,
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder "GPO not applicable to target per security filtering\n");
46947810076241f06f3e2919edb2289ed84d6c15Christian Maeder continue;
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder }
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder }
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder
996a56a455d65cfac4ddedd44fd90cfc1ea849aeChristian Maeder dacl_filtered_gpos[gpo_dn_idx] = NULL;
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder *_dacl_filtered_gpos = talloc_steal(mem_ctx, dacl_filtered_gpos);
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder *_num_dacl_filtered_gpos = gpo_dn_idx;
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder
1af66b491a6164e07ac202abfa0d06c6c2462d64Christian Maeder ret = EOK;
6b00a9239fe7c804524099ca3d25f4ffc6079ceeChristian Maeder
done:
talloc_free(tmp_ctx);
return ret;
}
/*
* This function determines whether the input cse_guid matches any of the input
* gpo_cse_guids. The boolean result is assigned to the _included output param.
*/
static bool
ad_gpo_includes_cse_guid(const char *cse_guid,
const char **gpo_cse_guids,
int num_gpo_cse_guids)
{
int i = 0;
const char *gpo_cse_guid = NULL;
for (i = 0; i < num_gpo_cse_guids; i++) {
gpo_cse_guid = gpo_cse_guids[i];
if (strcmp(gpo_cse_guid, cse_guid) == 0) {
return true;
}
}
return false;
}
/*
* This function takes an input dacl_filtered_gpos list, filters out any gpo
* that does not contain the input cse_guid, and assigns the result to the
* _cse_filtered_gpos output parameter.
*/
static errno_t
ad_gpo_filter_gpos_by_cse_guid(TALLOC_CTX *mem_ctx,
const char *cse_guid,
struct gp_gpo **dacl_filtered_gpos,
int num_dacl_filtered_gpos,
struct gp_gpo ***_cse_filtered_gpos,
int *_num_cse_filtered_gpos)
{
TALLOC_CTX *tmp_ctx = NULL;
int i = 0;
int ret = 0;
struct gp_gpo *dacl_filtered_gpo = NULL;
int gpo_dn_idx = 0;
struct gp_gpo **cse_filtered_gpos = NULL;
bool included;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
ret = ENOMEM;
goto done;
}
cse_filtered_gpos = talloc_array(tmp_ctx,
struct gp_gpo *,
num_dacl_filtered_gpos + 1);
if (cse_filtered_gpos == NULL) {
ret = ENOMEM;
goto done;
}
for (i = 0; i < num_dacl_filtered_gpos; i++) {
dacl_filtered_gpo = dacl_filtered_gpos[i];
DEBUG(SSSDBG_TRACE_ALL, "examining cse candidate_gpo_guid: %s\n",
dacl_filtered_gpo->gpo_guid);
included = ad_gpo_includes_cse_guid(cse_guid,
dacl_filtered_gpo->gpo_cse_guids,
dacl_filtered_gpo->num_gpo_cse_guids);
if (included) {
DEBUG(SSSDBG_TRACE_ALL,
"GPO applicable to target per cse_guid filtering\n");
cse_filtered_gpos[gpo_dn_idx] = talloc_steal(cse_filtered_gpos,
dacl_filtered_gpo);
dacl_filtered_gpos[i] = NULL;
gpo_dn_idx++;
} else {
DEBUG(SSSDBG_TRACE_ALL,
"GPO not applicable to target per cse_guid filtering\n");
continue;
}
}
cse_filtered_gpos[gpo_dn_idx] = NULL;
*_cse_filtered_gpos = talloc_steal(mem_ctx, cse_filtered_gpos);
*_num_cse_filtered_gpos = gpo_dn_idx;
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
/*
* This cse-specific function (GP_EXT_GUID_SECURITY) returns a boolean value
* based on whether the input user_sid or any of the input group_sids appear
* in the input list of privilege_sids.
*/
static bool
check_rights(char **privilege_sids,
int privilege_size,
const char *user_sid,
const char **group_sids,
int group_size)
{
int i, j;
for (i = 0; i < privilege_size; i++) {
if (strcmp(user_sid, privilege_sids[i]) == 0) {
return true;
}
for (j = 0; j < group_size; j++) {
if (strcmp(group_sids[j], privilege_sids[i]) == 0) {
return true;
}
}
}
return false;
}
/*
* This function parses the input ini_config object (which represents
* the cse-specific filename), and returns the policy_setting_value
* corresponding to the input policy_setting_key.
*/
static errno_t
ad_gpo_extract_policy_setting(TALLOC_CTX *mem_ctx,
struct ini_cfgobj *ini_config,
const char *policy_setting_key,
char **_policy_setting_value)
{
struct value_obj *vobj = NULL;
int ret;
const char *policy_setting_value;
ret = ini_get_config_valueobj(RIGHTS_SECTION, policy_setting_key, ini_config,
INI_GET_FIRST_VALUE, &vobj);
if (ret != 0) {
DEBUG(SSSDBG_CRIT_FAILURE,
"ini_get_config_valueobj failed [%d][%s]\n", ret, strerror(ret));
goto done;
}
if (vobj == NULL) {
DEBUG(SSSDBG_TRACE_ALL, "section/name not found: [%s][%s]\n",
RIGHTS_SECTION, policy_setting_key);
ret = ENOENT;
goto done;
}
policy_setting_value = ini_get_string_config_value(vobj, &ret);
if (ret != 0) {
DEBUG(SSSDBG_CRIT_FAILURE,
"ini_get_string_config_value failed [%d][%s]\n",
ret, strerror(ret));
goto done;
}
if (policy_setting_value[0]) {
*_policy_setting_value = talloc_strdup(mem_ctx, policy_setting_value);
if (!*_policy_setting_value) {
ret = ENOMEM;
goto done;
}
} else {
/* This is an explicitly empty policy setting.
* We need to remove this from the LDB.
*/
*_policy_setting_value = NULL;
}
ret = EOK;
done:
return ret;
}
/*
* This function parses the cse-specific (GP_EXT_GUID_SECURITY) filename,
* and stores the allow_key and deny_key of all of the gpo_map_types present
* in the file (as part of the GPO Result object in the sysdb cache).
*/
static errno_t
ad_gpo_store_policy_settings(struct sss_domain_info *domain,
const char *filename)
{
struct ini_cfgfile *file_ctx = NULL;
struct ini_cfgobj *ini_config = NULL;
int ret;
int i;
char *allow_value = NULL;
char *deny_value = NULL;
const char *allow_key = NULL;
const char *deny_key = NULL;
TALLOC_CTX *tmp_ctx = NULL;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
ret = ENOMEM;
goto done;
}
ret = ini_config_create(&ini_config);
if (ret != 0) {
DEBUG(SSSDBG_CRIT_FAILURE,
"ini_config_create failed [%d][%s]\n", ret, strerror(ret));
goto done;
}
ret = ini_config_file_open(filename, 0, &file_ctx);
if (ret != 0) {
DEBUG(SSSDBG_CRIT_FAILURE,
"ini_config_file_open failed [%d][%s]\n", ret, strerror(ret));
goto done;
}
ret = ini_config_parse(file_ctx, INI_STOP_ON_NONE, 0, 0, ini_config);
if (ret != 0) {
DEBUG(SSSDBG_CRIT_FAILURE,
"ini_config_parse failed [%d][%s]\n", ret, strerror(ret));
goto done;
}
for (i = 0; i < GPO_MAP_NUM_OPTS; i++) {
struct gpo_map_option_entry entry = gpo_map_option_entries[i];
allow_key = entry.allow_key;
if (allow_key != NULL) {
DEBUG(SSSDBG_TRACE_ALL, "allow_key = %s\n", allow_key);
ret = ad_gpo_extract_policy_setting(tmp_ctx,
ini_config,
allow_key,
&allow_value);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_CRIT_FAILURE,
"ad_gpo_extract_policy_setting failed for %s [%d][%s]\n",
allow_key, ret, strerror(ret));
goto done;
} else if (ret != ENOENT) {
ret = sysdb_gpo_store_gpo_result_setting(domain,
allow_key,
allow_value);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"sysdb_gpo_store_gpo_result_setting failed for key:"
"'%s' value:'%s' [%d][%s]\n", allow_key, allow_value,
ret, sss_strerror(ret));
goto done;
}
}
}
deny_key = entry.deny_key;
if (deny_key != NULL) {
DEBUG(SSSDBG_TRACE_ALL, "deny_key = %s\n", deny_key);
ret = ad_gpo_extract_policy_setting(tmp_ctx,
ini_config,
deny_key,
&deny_value);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_CRIT_FAILURE,
"ad_gpo_extract_policy_setting failed for %s [%d][%s]\n",
deny_key, ret, strerror(ret));
goto done;
} else if (ret != ENOENT) {
ret = sysdb_gpo_store_gpo_result_setting(domain,
deny_key,
deny_value);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"sysdb_gpo_store_gpo_result_setting failed for key:"
"'%s' value:'%s' [%d][%s]\n", deny_key, deny_value,
ret, sss_strerror(ret));
goto done;
}
}
}
}
ret = EOK;
done:
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Error encountered: %d.\n", ret);
}
ini_config_file_destroy(file_ctx);
ini_config_destroy(ini_config);
talloc_free(tmp_ctx);
return ret;
}
/*
* This cse-specific function (GP_EXT_GUID_SECURITY) performs the access
* check for determining whether logon access is granted or denied for
* the {user,domain} tuple specified in the inputs. This function returns EOK
* to indicate that access is granted. Any other return value indicates that
* access is denied.
*
* The access control algorithm first determines whether the "principal_sids"
* (i.e. user_sid or group_sids) appear in allowed_sids and denied_sids.
*
* For access to be granted, both the "allowed_sids_condition" *and* the
* "denied_sids_condition" must be met (in all other cases, access is denied).
* 1) The "allowed_sids_condition" is satisfied if any of the principal_sids
* appears in allowed_sids OR if the allowed_sids list is empty
* 2) The "denied_sids_condition" is satisfied if none of the principal_sids
* appear in denied_sids
*
* Note that a deployment that is unaware of GPO-based access-control policy
* settings is unaffected by them (b/c absence of allowed_sids grants access).
*
* Note that if a principal_sid appears in both allowed_sids and denied_sids,
* the "allowed_sids_condition" is met, but the "denied_sids_condition" is not.
* In other words, Deny takes precedence over Allow.
*/
static errno_t
ad_gpo_access_check(TALLOC_CTX *mem_ctx,
enum gpo_access_control_mode gpo_mode,
enum gpo_map_type gpo_map_type,
const char *user,
struct sss_domain_info *domain,
char **allowed_sids,
int allowed_size,
char **denied_sids,
int denied_size)
{
const char *user_sid;
const char **group_sids;
int group_size = 0;
bool access_granted = false;
bool access_denied = false;
int ret;
int j;
DEBUG(SSSDBG_TRACE_FUNC, "RESULTANT POLICY:\n");
DEBUG(SSSDBG_TRACE_FUNC, "gpo_map_type: %s\n",
gpo_map_type_string(gpo_map_type));
DEBUG(SSSDBG_TRACE_FUNC, "allowed_size = %d\n", allowed_size);
for (j= 0; j < allowed_size; j++) {
DEBUG(SSSDBG_TRACE_FUNC, "allowed_sids[%d] = %s\n", j, allowed_sids[j]);
}
DEBUG(SSSDBG_TRACE_FUNC, "denied_size = %d\n", denied_size);
for (j= 0; j < denied_size; j++) {
DEBUG(SSSDBG_TRACE_FUNC, " denied_sids[%d] = %s\n", j, denied_sids[j]);
}
ret = ad_gpo_get_sids(mem_ctx, user, domain, &user_sid,
&group_sids, &group_size);
if (ret != EOK) {
ret = ERR_NO_SIDS;
DEBUG(SSSDBG_OP_FAILURE,
"Unable to retrieve SIDs: [%d](%s)\n", ret, sss_strerror(ret));
goto done;
}
DEBUG(SSSDBG_TRACE_FUNC, "CURRENT USER:\n");
DEBUG(SSSDBG_TRACE_FUNC, " user_sid = %s\n", user_sid);
for (j= 0; j < group_size; j++) {
DEBUG(SSSDBG_TRACE_FUNC, " group_sids[%d] = %s\n", j,
group_sids[j]);
}
if (allowed_size == 0) {
access_granted = true;
} else {
access_granted = check_rights(allowed_sids, allowed_size, user_sid,
group_sids, group_size);
}
DEBUG(SSSDBG_TRACE_FUNC, "POLICY DECISION:\n");
DEBUG(SSSDBG_TRACE_FUNC, " access_granted = %d\n", access_granted);
access_denied = check_rights(denied_sids, denied_size, user_sid,
group_sids, group_size);
DEBUG(SSSDBG_TRACE_FUNC, " access_denied = %d\n", access_denied);
if (access_granted && !access_denied) {
return EOK;
} else {
switch (gpo_mode) {
case GPO_ACCESS_CONTROL_ENFORCING:
return ERR_ACCESS_DENIED;
case GPO_ACCESS_CONTROL_PERMISSIVE:
DEBUG(SSSDBG_TRACE_FUNC, "access denied: permissive mode\n");
sss_log_ext(SSS_LOG_WARNING, LOG_AUTHPRIV, "Warning: user would " \
"have been denied GPO-based logon access if the " \
"ad_gpo_access_control option were set to enforcing " \
"mode.");
return EOK;
default:
return EINVAL;
}
}
done:
if (ret) {
DEBUG(SSSDBG_CRIT_FAILURE, "Error encountered: %d.\n", ret);
}
return ret;
}
#define GPO_CHILD_LOG_FILE "gpo_child"
static errno_t gpo_child_init(void)
{
return child_debug_init(GPO_CHILD_LOG_FILE, &gpo_child_debug_fd);
}
/*
* This function retrieves the raw policy_setting_value for the input key from
* the GPO_Result object in the sysdb cache. It then parses the raw value and
* uses the results to populate the output parameters with the sids_list and
* the size of the sids_list.
*/
errno_t
parse_policy_setting_value(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
const char *key,
char ***_sids_list,
int *_sids_list_size)
{
int ret;
int i;
const char *value;
int sids_list_size;
char **sids_list = NULL;
ret = sysdb_gpo_get_gpo_result_setting(mem_ctx, domain, key, &value);
if (ret == ENOENT) {
DEBUG(SSSDBG_TRACE_FUNC, "No previous GPO result\n");
value = NULL;
} else if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot retrieve settings from sysdb for key: '%s' [%d][%s].\n",
key, ret, sss_strerror(ret));
goto done;
}
if (value == NULL) {
DEBUG(SSSDBG_TRACE_FUNC,
"No value for key [%s] found in gpo result\n", key);
sids_list_size = 0;
} else {
ret = split_on_separator(mem_ctx, value, ',', true, true,
&sids_list, &sids_list_size);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot parse list of sids %s: %d\n", value, ret);
ret = EINVAL;
goto done;
}
for (i = 0; i < sids_list_size; i++) {
/* remove the asterisk prefix found on sids */
sids_list[i]++;
}
}
*_sids_list = talloc_steal(mem_ctx, sids_list);
*_sids_list_size = sids_list_size;
ret = EOK;
done:
return ret;
}
/*
* This cse-specific function (GP_EXT_GUID_SECURITY) performs HBAC policy
* processing and determines whether logon access is granted or denied for
* the {user,domain} tuple specified in the inputs. This function returns EOK
* to indicate that access is granted. Any other return value indicates that
* access is denied.
*
* Internally, this function retrieves the allow_value and deny_value for the
* input gpo_map_type from the GPO Result object in the sysdb cache, parses
* the values into allow_sids and deny_sids, and executes the access control
* algorithm which compares the allow_sids and deny_sids against the user_sid
* and group_sids for the input user.
*/
static errno_t
ad_gpo_perform_hbac_processing(TALLOC_CTX *mem_ctx,
enum gpo_access_control_mode gpo_mode,
enum gpo_map_type gpo_map_type,
const char *user,
struct sss_domain_info *domain)
{
int ret;
const char *allow_key = NULL;
char **allow_sids;
int allow_size ;
const char *deny_key = NULL;
char **deny_sids;
int deny_size;
allow_key = gpo_map_option_entries[gpo_map_type].allow_key;
DEBUG(SSSDBG_TRACE_ALL, "allow_key: %s\n", allow_key);
deny_key = gpo_map_option_entries[gpo_map_type].deny_key;
DEBUG(SSSDBG_TRACE_ALL, "deny_key: %s\n", deny_key);
ret = parse_policy_setting_value(mem_ctx, domain, allow_key,
&allow_sids, &allow_size);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"parse_policy_setting_value failed for key %s: [%d](%s)\n",
allow_key, ret, sss_strerror(ret));
ret = EINVAL;
goto done;
}
ret = parse_policy_setting_value(mem_ctx, domain, deny_key,
&deny_sids, &deny_size);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"parse_policy_setting_value failed for key %s: [%d](%s)\n",
deny_key, ret, sss_strerror(ret));
ret = EINVAL;
goto done;
}
/* perform access check with the final resultant allow_sids and deny_sids */
ret = ad_gpo_access_check(mem_ctx, gpo_mode, gpo_map_type, user, domain,
allow_sids, allow_size, deny_sids, deny_size);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"GPO access check failed: [%d](%s)\n",
ret, strerror(ret));
goto done;
}
done:
return ret;
}
/* == ad_gpo_access_send/recv implementation ================================*/
struct ad_gpo_access_state {
struct tevent_context *ev;
struct ldb_context *ldb_ctx;
enum gpo_access_control_mode gpo_mode;
enum gpo_map_type gpo_map_type;
struct sdap_id_conn_ctx *conn;
struct sdap_id_op *sdap_op;
char *server_hostname;
struct sdap_options *opts;
int timeout;
struct sss_domain_info *domain;
const char *user;
int gpo_timeout_option;
const char *ad_hostname;
const char *target_dn;
struct gp_gpo **dacl_filtered_gpos;
int num_dacl_filtered_gpos;
struct gp_gpo **cse_filtered_gpos;
int num_cse_filtered_gpos;
int cse_gpo_index;
};
static void ad_gpo_connect_done(struct tevent_req *subreq);
static void ad_gpo_target_dn_retrieval_done(struct tevent_req *subreq);
static void ad_gpo_process_som_done(struct tevent_req *subreq);
static void ad_gpo_process_gpo_done(struct tevent_req *subreq);
static errno_t ad_gpo_cse_step(struct tevent_req *req);
static void ad_gpo_cse_done(struct tevent_req *subreq);
struct tevent_req *
ad_gpo_access_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct sss_domain_info *domain,
struct ad_access_ctx *ctx,
const char *user,
const char *service)
{
struct tevent_req *req;
struct tevent_req *subreq;
struct ad_gpo_access_state *state;
char *server_uri;
LDAPURLDesc *lud;
errno_t ret;
int hret;
hash_key_t key;
hash_value_t val;
enum gpo_map_type gpo_map_type;
/* setup logging for gpo child */
gpo_child_init();
req = tevent_req_create(mem_ctx, &state, struct ad_gpo_access_state);
if (req == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
return NULL;
}
/* determine service's option_type (e.g. interactive, network, etc) */
key.type = HASH_KEY_STRING;
key.str = talloc_strdup(state, service);
hret = hash_lookup(ctx->gpo_map_options_table, &key, &val);
if (hret != HASH_SUCCESS && hret != HASH_ERROR_KEY_NOT_FOUND) {
DEBUG(SSSDBG_OP_FAILURE, "Error checking hash table: [%s]\n",
hash_error_string(hret));
ret = EINVAL;
goto immediately;
}
/* if service isn't mapped, map it to value of ad_gpo_default_right option */
if (hret == HASH_ERROR_KEY_NOT_FOUND) {
DEBUG(SSSDBG_TRACE_FUNC, "using default right\n");
gpo_map_type = ctx->gpo_default_right;
} else {
gpo_map_type = (enum gpo_map_type) val.i;
}
DEBUG(SSSDBG_TRACE_FUNC, "service %s maps to %s\n", service,
gpo_map_type_string(gpo_map_type));
if (gpo_map_type == GPO_MAP_PERMIT) {
ret = EOK;
tevent_req_done(req);
tevent_req_post(req, ev);
goto immediately;
}
if (gpo_map_type == GPO_MAP_DENY) {
switch (ctx->gpo_access_control_mode) {
case GPO_ACCESS_CONTROL_ENFORCING:
ret = ERR_ACCESS_DENIED;
goto immediately;
case GPO_ACCESS_CONTROL_PERMISSIVE:
DEBUG(SSSDBG_TRACE_FUNC, "access denied: permissive mode\n");
sss_log_ext(SSS_LOG_WARNING, LOG_AUTHPRIV, "Warning: user would " \
"have been denied GPO-based logon access if the " \
"ad_gpo_access_control option were set to enforcing " \
"mode.");
ret = EOK;
tevent_req_done(req);
tevent_req_post(req, ev);
goto immediately;
default:
ret = EINVAL;
goto immediately;
}
}
state->gpo_map_type = gpo_map_type;
state->domain = domain;
state->dacl_filtered_gpos = NULL;
state->num_dacl_filtered_gpos = 0;
state->cse_filtered_gpos = NULL;
state->num_cse_filtered_gpos = 0;
state->cse_gpo_index = 0;
state->ev = ev;
state->user = user;
state->ldb_ctx = sysdb_ctx_get_ldb(domain->sysdb);
state->gpo_mode = ctx->gpo_access_control_mode;
state->gpo_timeout_option = ctx->gpo_cache_timeout;
state->ad_hostname = dp_opt_get_string(ctx->ad_options, AD_HOSTNAME);
state->opts = ctx->sdap_access_ctx->id_ctx->opts;
state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
state->conn = ad_get_dom_ldap_conn(ctx->ad_id_ctx, domain);
state->sdap_op = sdap_id_op_create(state, state->conn->conn_cache);
if (state->sdap_op == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed.\n");
ret = ENOMEM;
goto immediately;
}
/* extract server_hostname from server_uri */
server_uri = state->conn->service->uri;
ret = ldap_url_parse(server_uri, &lud);
if (ret != LDAP_SUCCESS) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to parse ldap URI (%s)!\n", server_uri);
ret = EINVAL;
goto immediately;
}
if (lud->lud_host == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE,
"The LDAP URI (%s) did not contain a host name\n", server_uri);
ldap_free_urldesc(lud);
ret = EINVAL;
goto immediately;
}
state->server_hostname = talloc_strdup(state, lud->lud_host);
ldap_free_urldesc(lud);
if (!state->server_hostname) {
ret = ENOMEM;
goto immediately;
}
DEBUG(SSSDBG_TRACE_ALL, "server_hostname from uri: %s\n",
state->server_hostname);
subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
if (subreq == NULL) {
DEBUG(SSSDBG_OP_FAILURE,
"sdap_id_op_connect_send failed: [%d](%s)\n",
ret, sss_strerror(ret));
goto immediately;
}
tevent_req_set_callback(subreq, ad_gpo_connect_done, req);
ret = EOK;
immediately:
if (ret != EOK) {
tevent_req_error(req, ret);
tevent_req_post(req, ev);
}
return req;
}
static errno_t
process_offline_gpos(TALLOC_CTX *mem_ctx,
const char *user,
enum gpo_access_control_mode gpo_mode,
struct sss_domain_info *domain,
enum gpo_map_type gpo_map_type)
{
errno_t ret;
ret = ad_gpo_perform_hbac_processing(mem_ctx,
gpo_mode,
gpo_map_type,
user,
domain);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "HBAC processing failed: [%d](%s}\n",
ret, sss_strerror(ret));
goto done;
}
/* we have successfully processed all offline gpos */
ret = EOK;
done:
return ret;
}
static void
ad_gpo_connect_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct ad_gpo_access_state *state;
char *filter;
char *sam_account_name;
char *domain_dn;
int dp_error;
errno_t ret;
const char *attrs[] = {AD_AT_DN, AD_AT_UAC, NULL};
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct ad_gpo_access_state);
ret = sdap_id_op_connect_recv(subreq, &dp_error);
talloc_zfree(subreq);
if (ret != EOK) {
if (dp_error != DP_ERR_OFFLINE) {
DEBUG(SSSDBG_OP_FAILURE,
"Failed to connect to AD server: [%d](%s)\n",
ret, strerror(ret));
goto done;
} else {
DEBUG(SSSDBG_TRACE_FUNC, "Preparing for offline operation.\n");
ret = process_offline_gpos(state,
state->user,
state->gpo_mode,
state->domain,
state->gpo_map_type);
if (ret == EOK) {
DEBUG(SSSDBG_TRACE_FUNC, "process_offline_gpos succeeded\n");
tevent_req_done(req);
goto done;
} else {
DEBUG(SSSDBG_OP_FAILURE,
"process_offline_gpos failed [%d](%s)\n",
ret, sss_strerror(ret));
goto done;
}
}
}
sam_account_name = sss_krb5_get_primary(state, "%S$", state->ad_hostname);
if (sam_account_name == NULL) {
ret = ENOMEM;
goto done;
}
DEBUG(SSSDBG_TRACE_FUNC, "sam_account_name is %s\n", sam_account_name);
/* Convert the domain name into domain DN */
ret = domain_to_basedn(state, state->domain->name, &domain_dn);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot convert domain name [%s] to base DN [%d]: %s\n",
state->domain->name, ret, sss_strerror(ret));
goto done;
}
/* SDAP_OC_USER objectclass covers both users and computers */
filter = talloc_asprintf(state,
"(&(objectclass=%s)(%s=%s))",
state->opts->user_map[SDAP_OC_USER].name,
state->opts->user_map[SDAP_AT_USER_NAME].name,
sam_account_name);
talloc_zfree(sam_account_name);
if (filter == NULL) {
ret = ENOMEM;
goto done;
}
subreq = sdap_get_generic_send(state, state->ev, state->opts,
sdap_id_op_handle(state->sdap_op),
domain_dn, LDAP_SCOPE_SUBTREE,
filter, attrs, NULL, 0,
state->timeout,
false);
if (subreq == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
ret = EIO;
goto done;
}
tevent_req_set_callback(subreq, ad_gpo_target_dn_retrieval_done, req);
ret = EOK;
done:
if (ret != EOK) {
tevent_req_error(req, ret);
}
}
static void
ad_gpo_target_dn_retrieval_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct ad_gpo_access_state *state;
int ret;
int dp_error;
size_t reply_count;
struct sysdb_attrs **reply;
const char *target_dn = NULL;
uint32_t uac;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct ad_gpo_access_state);
ret = sdap_get_generic_recv(subreq, state,
&reply_count, &reply);
talloc_zfree(subreq);
if (ret != EOK) {
ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
DEBUG(SSSDBG_OP_FAILURE,
"Unable to get policy target's DN: [%d](%s)\n",
ret, sss_strerror(ret));
ret = ENOENT;
goto done;
}
/* make sure there is only one non-NULL reply returned */
if (reply_count < 1) {
DEBUG(SSSDBG_OP_FAILURE, "No DN retrieved for policy target.\n");
ret = ENOENT;
goto done;
} else if (reply_count > 1) {
DEBUG(SSSDBG_OP_FAILURE, "Multiple replies for policy target\n");
ret = ERR_INTERNAL;
goto done;
} else if (reply == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "reply_count is 1, but reply is NULL\n");
ret = ERR_INTERNAL;
goto done;
}
/* reply[0] holds requested attributes of single reply */
ret = sysdb_attrs_get_string(reply[0], AD_AT_DN, &target_dn);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"sysdb_attrs_get_string failed: [%d](%s)\n",
ret, sss_strerror(ret));
goto done;
}
state->target_dn = talloc_steal(state, target_dn);
if (state->target_dn == NULL) {
ret = ENOMEM;
goto done;
}
ret = sysdb_attrs_get_uint32_t(reply[0], AD_AT_UAC, &uac);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"sysdb_attrs_get_uint32_t failed: [%d](%s)\n",
ret, sss_strerror(ret));
goto done;
}
/* we only support computer policy targets, not users */
if (!(uac & UAC_WORKSTATION_TRUST_ACCOUNT)) {
ret = EINVAL;
goto done;
}
subreq = ad_gpo_process_som_send(state,
state->ev,
state->conn,
state->ldb_ctx,
state->sdap_op,
state->opts,
state->timeout,
state->target_dn,
state->domain->name);
if (subreq == NULL) {
ret = ENOMEM;
goto done;
}
tevent_req_set_callback(subreq, ad_gpo_process_som_done, req);
ret = EOK;
done:
if (ret != EOK) {
tevent_req_error(req, ret);
}
}
static void
ad_gpo_process_som_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct ad_gpo_access_state *state;
int ret;
struct gp_som **som_list;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct ad_gpo_access_state);
ret = ad_gpo_process_som_recv(subreq, state, &som_list);
talloc_zfree(subreq);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Unable to get som list: [%d](%s)\n",
ret, sss_strerror(ret));
ret = ENOENT;
goto done;
}
subreq = ad_gpo_process_gpo_send(state,
state->ev,
state->sdap_op,
state->opts,
state->server_hostname,
state->timeout,
som_list);
if (subreq == NULL) {
ret = ENOMEM;
goto done;
}
tevent_req_set_callback(subreq, ad_gpo_process_gpo_done, req);
ret = EOK;
done:
if (ret != EOK) {
tevent_req_error(req, ret);
}
}
/*
* This function retrieves a list of candidate_gpos and potentially reduces it
* to a list of dacl_filtered_gpos, based on each GPO's DACL.
*
* This function then takes the list of dacl_filtered_gpos and potentially
* reduces it to a list of cse_filtered_gpos, based on whether each GPO's list
* of cse_guids includes the "SecuritySettings" CSE GUID (used for HBAC).
*
* Ultimately, this function then sends each cse_filtered_gpo to the gpo_child,
* which retrieves the GPT.INI and policy files (as needed). Once all files
* have been downloaded, the ad_gpo_cse_done function performs HBAC processing.
*/
static void
ad_gpo_process_gpo_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct ad_gpo_access_state *state;
int ret;
int dp_error;
struct gp_gpo **candidate_gpos = NULL;
int num_candidate_gpos = 0;
int i = 0;
const char **cse_filtered_gpo_guids;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct ad_gpo_access_state);
ret = ad_gpo_process_gpo_recv(subreq, state, &candidate_gpos,
&num_candidate_gpos);
talloc_zfree(subreq);
ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Unable to get GPO list: [%d](%s)\n",
ret, sss_strerror(ret));
ret = ENOENT;
goto done;
}
ret = ad_gpo_filter_gpos_by_dacl(state, state->user, state->domain,
state->opts->idmap_ctx->map,
candidate_gpos, num_candidate_gpos,
&state->dacl_filtered_gpos,
&state->num_dacl_filtered_gpos);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Unable to filter GPO list by DACKL: [%d](%s)\n",
ret, sss_strerror(ret));
goto done;
}
if (state->dacl_filtered_gpos[0] == NULL) {
/* since no applicable gpos were found, there is nothing to enforce */
DEBUG(SSSDBG_TRACE_FUNC,
"no applicable gpos found after dacl filtering\n");
ret = EOK;
goto done;
}
for (i = 0; i < state->num_dacl_filtered_gpos; i++) {
DEBUG(SSSDBG_TRACE_FUNC, "dacl_filtered_gpos[%d]->gpo_guid is %s\n", i,
state->dacl_filtered_gpos[i]->gpo_guid);
}
ret = ad_gpo_filter_gpos_by_cse_guid(state,
GP_EXT_GUID_SECURITY,
state->dacl_filtered_gpos,
state->num_dacl_filtered_gpos,
&state->cse_filtered_gpos,
&state->num_cse_filtered_gpos);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Unable to filter GPO list by CSE_GUID: [%d](%s)\n",
ret, strerror(ret));
goto done;
}
if (state->cse_filtered_gpos[0] == NULL) {
/* no gpos contain "SecuritySettings" cse_guid, nothing to enforce */
DEBUG(SSSDBG_TRACE_FUNC,
"no applicable gpos found after cse_guid filtering\n");
ret = EOK;
goto done;
}
/* we create and populate an array of applicable gpo-guids */
cse_filtered_gpo_guids =
talloc_array(state, const char *, state->num_cse_filtered_gpos);
if (cse_filtered_gpo_guids == NULL) {
ret = ENOMEM;
goto done;
}
for (i = 0; i < state->num_cse_filtered_gpos; i++) {
DEBUG(SSSDBG_TRACE_FUNC, "cse_filtered_gpos[%d]->gpo_guid is %s\n", i,
state->cse_filtered_gpos[i]->gpo_guid);
cse_filtered_gpo_guids[i] = talloc_steal(cse_filtered_gpo_guids,
state->cse_filtered_gpos[i]->gpo_guid);
if (cse_filtered_gpo_guids[i] == NULL) {
ret = ENOMEM;
goto done;
}
}
DEBUG(SSSDBG_TRACE_FUNC, "num_cse_filtered_gpos: %d\n",
state->num_cse_filtered_gpos);
/*
* before we start processing each gpo, we delete the GPO Result object
* from the sysdb cache so that any previous policy settings are cleared;
* subsequent functions will add the GPO Result object (and populate it
* with resultant policy settings) for this policy application
*/
ret = sysdb_gpo_delete_gpo_result_object(state, state->domain);
if (ret != EOK) {
switch (ret) {
case ENOENT:
DEBUG(SSSDBG_TRACE_FUNC, "No GPO Result available in cache\n");
break;
default:
DEBUG(SSSDBG_FATAL_FAILURE,
"Could not delete GPO Result from cache: [%s]\n",
strerror(ret));
goto done;
}
}
ret = ad_gpo_cse_step(req);
done:
if (ret == EOK) {
tevent_req_done(req);
} else if (ret != EAGAIN) {
tevent_req_error(req, ret);
}
}
static errno_t
ad_gpo_cse_step(struct tevent_req *req)
{
struct tevent_req *subreq;
struct ad_gpo_access_state *state;
int i = 0;
struct ldb_result *res;
errno_t ret;
bool send_to_child = true;
int cached_gpt_version = 0;
time_t policy_file_timeout = 0;
state = tevent_req_data(req, struct ad_gpo_access_state);
struct gp_gpo *cse_filtered_gpo =
state->cse_filtered_gpos[state->cse_gpo_index];
/* cse_filtered_gpo is NULL after all GPO policy files have been downloaded */
if (cse_filtered_gpo == NULL) return EOK;
DEBUG(SSSDBG_TRACE_FUNC, "cse filtered_gpos[%d]->gpo_guid is %s\n",
state->cse_gpo_index, cse_filtered_gpo->gpo_guid);
for (i = 0; i < cse_filtered_gpo->num_gpo_cse_guids; i++) {
DEBUG(SSSDBG_TRACE_ALL,
"cse_filtered_gpos[%d]->gpo_cse_guids[%d]->gpo_guid is %s\n",
state->cse_gpo_index, i, cse_filtered_gpo->gpo_cse_guids[i]);
}
DEBUG(SSSDBG_TRACE_FUNC, "smb_server: %s\n", cse_filtered_gpo->smb_server);
DEBUG(SSSDBG_TRACE_FUNC, "smb_share: %s\n", cse_filtered_gpo->smb_share);
DEBUG(SSSDBG_TRACE_FUNC, "smb_path: %s\n", cse_filtered_gpo->smb_path);
DEBUG(SSSDBG_TRACE_FUNC, "gpo_guid: %s\n", cse_filtered_gpo->gpo_guid);
cse_filtered_gpo->policy_filename =
talloc_asprintf(state,
GPO_CACHE_PATH"%s%s",
cse_filtered_gpo->smb_path,
GP_EXT_GUID_SECURITY_SUFFIX);
if (cse_filtered_gpo->policy_filename == NULL) {
return ENOMEM;
}
/* retrieve gpo cache entry; set cached_gpt_version to -1 if unavailable */
DEBUG(SSSDBG_TRACE_FUNC, "retrieving GPO from cache [%s]\n",
cse_filtered_gpo->gpo_guid);
ret = sysdb_gpo_get_gpo_by_guid(state,
state->domain,
cse_filtered_gpo->gpo_guid,
&res);
if (ret == EOK) {
/*
* Note: if the timeout is valid, then we can later avoid downloading
* the GPT.INI file, as well as any policy files (i.e. we don't need
* to interact with the gpo_child at all). However, even if the timeout
* is not valid, while we will have to interact with the gpo child to
* download the GPT.INI file, we may still be able to avoid downloading
* the policy files (if the cached_gpt_version is the same as the
* GPT.INI version). In other words, the timeout is *not* an expiration
* for the entire cache entry; the cached_gpt_version never expires.
*/
cached_gpt_version = ldb_msg_find_attr_as_int(res->msgs[0],
SYSDB_GPO_VERSION_ATTR,
0);
policy_file_timeout = ldb_msg_find_attr_as_uint64
(res->msgs[0], SYSDB_GPO_TIMEOUT_ATTR, 0);
if (policy_file_timeout >= time(NULL)) {
send_to_child = false;
}
} else if (ret == ENOENT) {
DEBUG(SSSDBG_TRACE_FUNC, "ENOENT\n");
cached_gpt_version = -1;
} else {
DEBUG(SSSDBG_FATAL_FAILURE, "Could not read GPO from cache: [%s]\n",
strerror(ret));
return ret;
}
DEBUG(SSSDBG_TRACE_FUNC, "send_to_child: %d\n", send_to_child);
DEBUG(SSSDBG_TRACE_FUNC, "cached_gpt_version: %d\n", cached_gpt_version);
cse_filtered_gpo->send_to_child = send_to_child;
subreq = ad_gpo_process_cse_send(state,
state->ev,
send_to_child,
state->domain,
cse_filtered_gpo->gpo_guid,
cse_filtered_gpo->smb_server,
cse_filtered_gpo->smb_share,
cse_filtered_gpo->smb_path,
GP_EXT_GUID_SECURITY_SUFFIX,
cached_gpt_version,
state->gpo_timeout_option);
tevent_req_set_callback(subreq, ad_gpo_cse_done, req);
return EAGAIN;
}
/*
* This cse-specific function (GP_EXT_GUID_SECURITY) increments the
* cse_gpo_index until the policy settings for all applicable GPOs have been
* stored as part of the GPO Result object in the sysdb cache. Once all
* GPOs have been processed, this functions performs HBAC processing by
* comparing the resultant policy setting values in the GPO Result object
* with the user_sid/group_sids of interest.
*/
static void
ad_gpo_cse_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct ad_gpo_access_state *state;
int ret;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct ad_gpo_access_state);
struct gp_gpo *cse_filtered_gpo =
state->cse_filtered_gpos[state->cse_gpo_index];
const char *gpo_guid = cse_filtered_gpo->gpo_guid;
DEBUG(SSSDBG_TRACE_FUNC, "gpo_guid: %s\n", gpo_guid);
ret = ad_gpo_process_cse_recv(subreq);
talloc_zfree(subreq);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve policy data: [%d](%s}\n",
ret, sss_strerror(ret));
goto done;
}
/*
* now that the policy file for this gpo have been downloaded to the
* GPO CACHE, we store all of the supported keys present in the file
* (as part of the GPO Result object in the sysdb cache).
*/
ret = ad_gpo_store_policy_settings(state->domain,
cse_filtered_gpo->policy_filename);
state->cse_gpo_index++;
ret = ad_gpo_cse_step(req);
if (ret == EOK) {
/* ret is EOK only after all GPO policy files have been downloaded */
ret = ad_gpo_perform_hbac_processing(state,
state->gpo_mode,
state->gpo_map_type,
state->user,
state->domain);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "HBAC processing failed: [%d](%s}\n",
ret, sss_strerror(ret));
goto done;
}
}
done:
if (ret == EOK) {
tevent_req_done(req);
} else if (ret != EAGAIN) {
tevent_req_error(req, ret);
}
}
errno_t
ad_gpo_access_recv(struct tevent_req *req)
{
TEVENT_REQ_RETURN_ON_ERROR(req);
return EOK;
}
/* == ad_gpo_process_som_send/recv helpers ================================= */
/*
* This function returns the parent of an LDAP DN
*/
static errno_t
ad_gpo_parent_dn(TALLOC_CTX *mem_ctx,
struct ldb_context *ldb_ctx,
const char *dn,
const char **_parent_dn)
{
struct ldb_dn *ldb_dn;
struct ldb_dn *parent_ldb_dn;
const char *p;
int ret;
TALLOC_CTX *tmp_ctx = NULL;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
ret = ENOMEM;
goto done;
}
ldb_dn = ldb_dn_new(tmp_ctx, ldb_ctx, dn);
parent_ldb_dn = ldb_dn_get_parent(tmp_ctx, ldb_dn);
p = ldb_dn_get_linearized(parent_ldb_dn);
*_parent_dn = talloc_steal(mem_ctx, p);
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
/*
* This function populates the _som_list output parameter by parsing the input
* DN into a list of gp_som objects. This function essentially repeatedly
* appends the input DN's parent to the SOM List (if the parent starts with
* "OU=" or "DC="), until the first "DC=" component is reached.
* Example: if input DN is "CN=MyComputer,CN=Computers,OU=Sales,DC=FOO,DC=COM",
* then SOM List has 2 SOM entries: {[OU=Sales,DC=FOO,DC=COM], [DC=FOO, DC=COM]}
*/
static errno_t
ad_gpo_populate_som_list(TALLOC_CTX *mem_ctx,
struct ldb_context *ldb_ctx,
const char *target_dn,
int *_num_soms,
struct gp_som ***_som_list)
{
TALLOC_CTX *tmp_ctx = NULL;
int ret;
int rdn_count = 0;
int som_idx = 0;
struct gp_som **som_list;
const char *parent_dn = NULL;
const char *tmp_dn = NULL;
struct ldb_dn *ldb_target_dn;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
ret = ENOMEM;
goto done;
}
ldb_target_dn = ldb_dn_new(tmp_ctx, ldb_ctx, target_dn);
if (ldb_target_dn == NULL) {
ret = EINVAL;
goto done;
}
rdn_count = ldb_dn_get_comp_num(ldb_target_dn);
if (rdn_count == -1) {
ret = EINVAL;
goto done;
}
if (rdn_count == 0) {
*_som_list = NULL;
ret = EOK;
goto done;
}
/* assume the worst-case, in which every parent is a SOM */
/* include space for Site SOM and NULL: rdn_count + 1 + 1 */
som_list = talloc_array(tmp_ctx, struct gp_som *, rdn_count + 1 + 1);
if (som_list == NULL) {
ret = ENOMEM;
goto done;
}
/* first, populate the OU and Domain SOMs */
tmp_dn = target_dn;;
while ((ad_gpo_parent_dn(tmp_ctx, ldb_ctx, tmp_dn, &parent_dn)) == EOK) {
if ((strncasecmp(parent_dn, "OU=", strlen("OU=")) == 0) ||
(strncasecmp(parent_dn, "DC=", strlen("DC=")) == 0)) {
som_list[som_idx] = talloc_zero(som_list, struct gp_som);
if (som_list[som_idx] == NULL) {
ret = ENOMEM;
goto done;
}
som_list[som_idx]->som_dn = talloc_steal(som_list[som_idx],
parent_dn);
if (som_list[som_idx]->som_dn == NULL) {
ret = ENOMEM;
goto done;
}
som_idx++;
}
if (strncasecmp(parent_dn, "DC=", strlen("DC=")) == 0) {
break;
}
tmp_dn = parent_dn;
}
som_list[som_idx] = NULL;
*_num_soms = som_idx;
*_som_list = talloc_steal(mem_ctx, som_list);
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
/*
* This function populates the _gplink_list output parameter by parsing the
* input raw_gplink_value into an array of gp_gplink objects, each consisting of
* a GPO DN and bool enforced field.
*
* The raw_gplink_value is single string consisting of multiple gplink strings.
* The raw_gplink_value is in the following format:
* "[GPO_DN_1;GPLinkOptions_1]...[GPO_DN_n;GPLinkOptions_n]"
*
* Each gplink string consists of a GPO DN and a GPLinkOptions field (which
* indicates whether its associated GPO DN is ignored, unenforced, or enforced).
* If a GPO DN is flagged as ignored, it is discarded and will not be added to
* the _gplink_list. If the allow_enforced_only input is true, AND a GPO DN is
* flagged as unenforced, it will also be discarded.
*
* Example: if raw_gplink_value="[OU=Sales,DC=FOO,DC=COM;0][DC=FOO,DC=COM;2]"
* and allow_enforced_only=FALSE, then the output would consist of following:
* _gplink_list[0]: {GPO DN: "OU=Sales,DC=FOO,DC=COM", enforced: FALSE}
* _gplink_list[1]: {GPO DN: "DC=FOO,DC=COM", enforced: TRUE}
*/
static errno_t
ad_gpo_populate_gplink_list(TALLOC_CTX *mem_ctx,
const char *som_dn,
char *raw_gplink_value,
struct gp_gplink ***_gplink_list,
bool allow_enforced_only)
{
TALLOC_CTX *tmp_ctx = NULL;
char *ptr;
char *first;
char *last;
char *dn;
char *gplink_options;
const char delim = ']';
struct gp_gplink **gplink_list;
int i;
int ret;
uint32_t gplink_number;
int gplink_count = 0;
int num_enabled = 0;
if (raw_gplink_value == NULL ||
*raw_gplink_value == '\0' ||
_gplink_list == NULL) {
return EINVAL;
}
DEBUG(SSSDBG_TRACE_FUNC, "som_dn: %s\n", som_dn);
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
ret = ENOMEM;
goto done;
}
ptr = raw_gplink_value;
while ((ptr = strchr(ptr, delim))) {
ptr++;
gplink_count++;
}
if (gplink_count == 0) {
ret = EOK;
goto done;
}
gplink_list = talloc_array(tmp_ctx, struct gp_gplink *, gplink_count + 1);
if (gplink_list == NULL) {
ret = ENOMEM;
goto done;
}
num_enabled = 0;
ptr = raw_gplink_value;
for (i = 0; i < gplink_count; i++) {
first = ptr + 1;
last = strchr(first, delim);
if (last == NULL) {
ret = EINVAL;
goto done;
}
*last = '\0';
last++;
dn = first;
if ( strncasecmp(dn, "LDAP://", 7)== 0 ) {
dn = dn + 7;
}
gplink_options = strchr(first, ';');
if (gplink_options == NULL) {
ret = EINVAL;
goto done;
}
*gplink_options = '\0';
gplink_options++;
gplink_number = strtouint32(gplink_options, NULL, 10);
if (errno != 0) {
ret = errno;
DEBUG(SSSDBG_OP_FAILURE,
"strtouint32 failed: [%d](%s)\n", ret, sss_strerror(ret));
goto done;
}
DEBUG(SSSDBG_TRACE_ALL,
"gplink_list[%d]: [%s; %d]\n", num_enabled, dn, gplink_number);
if ((gplink_number == 1) || (gplink_number ==3)) {
/* ignore flag is set */
DEBUG(SSSDBG_TRACE_ALL, "ignored gpo skipped\n");
ptr = last;
continue;
}
if (allow_enforced_only && (gplink_number == 0)) {
/* unenforced flag is set; only enforced gpos allowed */
DEBUG(SSSDBG_TRACE_ALL, "unenforced gpo skipped\n");
ptr = last;
continue;
}
gplink_list[num_enabled] = talloc_zero(gplink_list, struct gp_gplink);
if (gplink_list[num_enabled] == NULL) {
ret = ENOMEM;
goto done;
}
gplink_list[num_enabled]->gpo_dn =
talloc_strdup(gplink_list[num_enabled], dn);
if (gplink_list[num_enabled]->gpo_dn == NULL) {
ret = ENOMEM;
goto done;
}
if (gplink_number == 0) {
gplink_list[num_enabled]->enforced = 0;
num_enabled++;
} else if (gplink_number == 2) {
gplink_list[num_enabled]->enforced = 1;
num_enabled++;
} else {
ret = EINVAL;
goto done;
}
ptr = last;
}
gplink_list[num_enabled] = NULL;
*_gplink_list = talloc_steal(mem_ctx, gplink_list);
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
/* == ad_gpo_process_som_send/recv implementation ========================== */
struct ad_gpo_process_som_state {
struct tevent_context *ev;
struct sdap_id_op *sdap_op;
struct sdap_options *opts;
int timeout;
bool allow_enforced_only;
char *site_name;
char *site_dn;
struct gp_som **som_list;
int som_index;
int num_soms;
};
static void ad_gpo_site_name_retrieval_done(struct tevent_req *subreq);
static void ad_gpo_site_dn_retrieval_done(struct tevent_req *subreq);
static errno_t ad_gpo_get_som_attrs_step(struct tevent_req *req);
static void ad_gpo_get_som_attrs_done(struct tevent_req *subreq);
/*
* This function uses the input target_dn and input domain_name to populate
* a list of gp_som objects. Each object in this list represents a SOM
* associated with the target (such as OU, Domain, and Site).
*
* The inputs are used to determine the DNs of each SOM associated with the
* target. In turn, the SOM object DNs are used to retrieve certain LDAP
* attributes of each SOM object, that are parsed into an array of gp_gplink
* objects, essentially representing the GPOs that have been linked to each
* SOM object. Note that it is perfectly valid for there to be *no* GPOs
* linked to a SOM object.
*/
struct tevent_req *
ad_gpo_process_som_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct sdap_id_conn_ctx *conn,
struct ldb_context *ldb_ctx,
struct sdap_id_op *sdap_op,
struct sdap_options *opts,
int timeout,
const char *target_dn,
const char *domain_name)
{
struct tevent_req *req;
struct tevent_req *subreq;
struct ad_gpo_process_som_state *state;
errno_t ret;
req = tevent_req_create(mem_ctx, &state, struct ad_gpo_process_som_state);
if (req == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
return NULL;
}
state->ev = ev;
state->sdap_op = sdap_op;
state->opts = opts;
state->timeout = timeout;
state->som_index = 0;
state->allow_enforced_only = 0;
ret = ad_gpo_populate_som_list(state, ldb_ctx, target_dn,
&state->num_soms, &state->som_list);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Unable to retrieve SOM List : [%d](%s)\n",
ret, sss_strerror(ret));
ret = ENOENT;
goto immediately;
}
if (state->som_list == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "target dn must have at least one parent\n");
ret = EINVAL;
goto immediately;
}
subreq = ad_master_domain_send(state, state->ev, conn,
state->sdap_op, domain_name);
if (subreq == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "ad_master_domain_send failed.\n");
ret = ENOMEM;
goto immediately;
}
tevent_req_set_callback(subreq, ad_gpo_site_name_retrieval_done, req);
ret = EOK;
immediately:
if (ret != EOK) {
tevent_req_error(req, ret);
tevent_req_post(req, ev);
}
return req;
}
static void
ad_gpo_site_name_retrieval_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct ad_gpo_process_som_state *state;
int ret;
char *site;
const char *attrs[] = {AD_AT_CONFIG_NC, NULL};
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct ad_gpo_process_som_state);
/* gpo code only cares about the site name */
ret = ad_master_domain_recv(subreq, state, NULL, NULL, &site, NULL);
talloc_zfree(subreq);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "Cannot retrieve master domain info\n");
tevent_req_error(req, ENOENT);
return;
}
state->site_name = talloc_asprintf(state, "cn=%s", site);
if (state->site_name == NULL) {
tevent_req_error(req, ENOMEM);
return;
}
/*
* note: the configNC attribute is being retrieved here from the rootDSE
* entry. In future, since we already make an LDAP query for the rootDSE
* entry when LDAP connection is made, this attribute should really be
* retrieved at that point (see https://fedorahosted.org/sssd/ticket/2276)
*/
subreq = sdap_get_generic_send(state, state->ev, state->opts,
sdap_id_op_handle(state->sdap_op),
"", LDAP_SCOPE_BASE,
"(objectclass=*)", attrs, NULL, 0,
state->timeout,
false);
if (subreq == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
tevent_req_error(req, ENOMEM);
return;
}
tevent_req_set_callback(subreq, ad_gpo_site_dn_retrieval_done, req);
}
static void
ad_gpo_site_dn_retrieval_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct ad_gpo_process_som_state *state;
int ret;
int dp_error;
int i = 0;
size_t reply_count;
struct sysdb_attrs **reply;
const char *configNC;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct ad_gpo_process_som_state);
ret = sdap_get_generic_recv(subreq, state,
&reply_count, &reply);
talloc_zfree(subreq);
if (ret != EOK) {
ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
DEBUG(SSSDBG_OP_FAILURE,
"Unable to get configNC: [%d](%s)\n", ret, sss_strerror(ret));
ret = ENOENT;
goto done;
}
/* make sure there is only one non-NULL reply returned */
if (reply_count < 1) {
DEBUG(SSSDBG_OP_FAILURE, "No configNC retrieved\n");
ret = ENOENT;
goto done;
} else if (reply_count > 1) {
DEBUG(SSSDBG_OP_FAILURE, "Multiple replies for configNC\n");
ret = ERR_INTERNAL;
goto done;
} else if (reply == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "reply_count is 1, but reply is NULL\n");
ret = ERR_INTERNAL;
goto done;
}
/* reply[0] holds requested attributes of single reply */
ret = sysdb_attrs_get_string(reply[0], AD_AT_CONFIG_NC, &configNC);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"sysdb_attrs_get_string failed: [%d](%s)\n",
ret, sss_strerror(ret));
goto done;
}
state->site_dn =
talloc_asprintf(state, "%s,cn=Sites,%s", state->site_name, configNC);
if (state->site_dn == NULL) {
ret = ENOMEM;
goto done;
}
/* note that space was allocated for site_dn when allocating som_list */
state->som_list[state->num_soms] =
talloc_zero(state->som_list, struct gp_som);
if (state->som_list[state->num_soms] == NULL) {
ret = ENOMEM;
goto done;
}
state->som_list[state->num_soms]->som_dn =
talloc_steal(state->som_list[state->num_soms], state->site_dn);
if (state->som_list[state->num_soms]->som_dn == NULL) {
ret = ENOMEM;
goto done;
}
state->num_soms++;
state->som_list[state->num_soms] = NULL;
i = 0;
while (state->som_list[i]) {
DEBUG(SSSDBG_TRACE_FUNC, "som_list[%d]->som_dn is %s\n", i,
state->som_list[i]->som_dn);
i++;
}
ret = ad_gpo_get_som_attrs_step(req);
done:
if (ret == EOK) {
tevent_req_done(req);
} else if (ret != EAGAIN) {
tevent_req_error(req, ret);
}
}
static errno_t
ad_gpo_get_som_attrs_step(struct tevent_req *req)
{
const char *attrs[] = {AD_AT_GPLINK, AD_AT_GPOPTIONS, NULL};
struct tevent_req *subreq;
struct ad_gpo_process_som_state *state;
state = tevent_req_data(req, struct ad_gpo_process_som_state);
struct gp_som *gp_som = state->som_list[state->som_index];
/* gp_som is NULL only after all SOMs have been processed */
if (gp_som == NULL) return EOK;
const char *som_dn = gp_som->som_dn;
subreq = sdap_get_generic_send(state, state->ev, state->opts,
sdap_id_op_handle(state->sdap_op),
som_dn, LDAP_SCOPE_BASE,
"(objectclass=*)", attrs, NULL, 0,
state->timeout,
false);
if (subreq == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
return ENOMEM;
}
tevent_req_set_callback(subreq, ad_gpo_get_som_attrs_done, req);
return EAGAIN;
}
static void
ad_gpo_get_som_attrs_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct ad_gpo_process_som_state *state;
int ret;
int dp_error;
size_t num_results;
struct sysdb_attrs **results;
struct ldb_message_element *el = NULL;
uint8_t *raw_gplink_value;
uint8_t *raw_gpoptions_value;
uint32_t allow_enforced_only = 0;
struct gp_som *gp_som;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct ad_gpo_process_som_state);
ret = sdap_get_generic_recv(subreq, state,
&num_results, &results);
talloc_zfree(subreq);
if (ret != EOK) {
ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
DEBUG(SSSDBG_OP_FAILURE,
"Unable to get SOM attributes: [%d](%s)\n",
ret, sss_strerror(ret));
ret = ENOENT;
goto done;
}
if ((num_results < 1) || (results == NULL)) {
DEBUG(SSSDBG_OP_FAILURE, "no attrs found for SOM; try next SOM.\n");
state->som_index++;
ret = ad_gpo_get_som_attrs_step(req);
goto done;
} else if (num_results > 1) {
DEBUG(SSSDBG_OP_FAILURE, "Received multiple replies\n");
ret = ERR_INTERNAL;
goto done;
}
/* Get the gplink value, if available */
ret = sysdb_attrs_get_el(results[0], AD_AT_GPLINK, &el);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_OP_FAILURE,
"sysdb_attrs_get_el() failed: [%d](%s)\n",
ret, sss_strerror(ret));
goto done;
}
if ((ret == ENOENT) || (el->num_values == 0)) {
DEBUG(SSSDBG_OP_FAILURE, "no attrs found for SOM; try next SOM\n");
state->som_index++;
ret = ad_gpo_get_som_attrs_step(req);
goto done;
}
raw_gplink_value = el[0].values[0].data;
ret = sysdb_attrs_get_el(results[0], AD_AT_GPOPTIONS, &el);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el() failed\n");
goto done;
}
if ((ret == ENOENT) || (el->num_values == 0)) {
DEBUG(SSSDBG_TRACE_ALL,
"gpoptions attr not found or has no value; defaults to 0\n");
allow_enforced_only = 0;
} else {
raw_gpoptions_value = el[0].values[0].data;
allow_enforced_only = strtouint32((char *)raw_gpoptions_value, NULL, 10);
if (errno != 0) {
ret = errno;
DEBUG(SSSDBG_OP_FAILURE,
"strtouint32 failed: [%d](%s)\n", ret, sss_strerror(ret));
goto done;
}
}
gp_som = state->som_list[state->som_index];
ret = ad_gpo_populate_gplink_list(gp_som,
gp_som->som_dn,
(char *)raw_gplink_value,
&gp_som->gplink_list,
state->allow_enforced_only);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"ad_gpo_populate_gplink_list() failed\n");
goto done;
}
if (allow_enforced_only) {
state->allow_enforced_only = 1;
}
state->som_index++;
ret = ad_gpo_get_som_attrs_step(req);
done:
if (ret == EOK) {
tevent_req_done(req);
} else if (ret != EAGAIN) {
tevent_req_error(req, ret);
}
}
int
ad_gpo_process_som_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
struct gp_som ***som_list)
{
struct ad_gpo_process_som_state *state =
tevent_req_data(req, struct ad_gpo_process_som_state);
TEVENT_REQ_RETURN_ON_ERROR(req);
*som_list = talloc_steal(mem_ctx, state->som_list);
return EOK;
}
/* == ad_gpo_process_gpo_send/recv helpers ================================= */
/*
* This function examines the gp_gplink objects in each gp_som object specified
* in the input som_list, and populates the _candidate_gpos output parameter's
* gpo_dn fields with prioritized list of GPO DNs. Prioritization ensures that:
* - GPOs linked to an OU will be applied after GPOs linked to a Domain,
* which will be applied after GPOs linked to a Site.
* - multiple GPOs linked to a single SOM are applied in their link order
* (i.e. 1st GPO linked to SOM is applied after 2nd GPO linked to SOM, etc).
* - enforced GPOs are applied after unenforced GPOs.
*
* As such, the _candidate_gpos output's dn fields looks like (in link order):
* [unenforced {Site, Domain, OU}; enforced {Site, Domain, OU}]
*
* Note that in the case of conflicting policy settings, GPOs appearing later
* in the list will trump GPOs appearing earlier in the list.
*/
static errno_t
ad_gpo_populate_candidate_gpos(TALLOC_CTX *mem_ctx,
struct gp_som **som_list,
struct gp_gpo ***_candidate_gpos,
int *_num_candidate_gpos)
{
TALLOC_CTX *tmp_ctx = NULL;
struct gp_som *gp_som = NULL;
struct gp_gplink *gp_gplink = NULL;
struct gp_gpo **candidate_gpos = NULL;
int num_candidate_gpos = 0;
const char **enforced_gpo_dns = NULL;
const char **unenforced_gpo_dns = NULL;
int gpo_dn_idx = 0;
int num_enforced = 0;
int enforced_idx = 0;
int num_unenforced = 0;
int unenforced_idx = 0;
int i = 0;
int j = 0;
int ret;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
ret = ENOMEM;
goto done;
}
while (som_list[i]) {
gp_som = som_list[i];
j = 0;
while (gp_som && gp_som->gplink_list && gp_som->gplink_list[j]) {
gp_gplink = gp_som->gplink_list[j];
if (gp_gplink == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "unexpected null gp_gplink\n");
ret = EINVAL;
goto done;
}
if (gp_gplink->enforced) {
num_enforced++;
} else {
num_unenforced++;
}
j++;
}
i++;
}
num_candidate_gpos = num_enforced + num_unenforced;
if (num_candidate_gpos == 0) {
*_candidate_gpos = NULL;
*_num_candidate_gpos = 0;
ret = EOK;
goto done;
}
enforced_gpo_dns = talloc_array(tmp_ctx, const char *, num_enforced + 1);
if (enforced_gpo_dns == NULL) {
ret = ENOMEM;
goto done;
}
unenforced_gpo_dns = talloc_array(tmp_ctx, const char *, num_unenforced + 1);
if (unenforced_gpo_dns == NULL) {
ret = ENOMEM;
goto done;
}
i = 0;
while (som_list[i]) {
gp_som = som_list[i];
j = 0;
while (gp_som && gp_som->gplink_list && gp_som->gplink_list[j]) {
gp_gplink = gp_som->gplink_list[j];
if (gp_gplink == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "unexpected null gp_gplink\n");
ret = EINVAL;
goto done;
}
if (gp_gplink->enforced) {
enforced_gpo_dns[enforced_idx] =
talloc_steal(enforced_gpo_dns, gp_gplink->gpo_dn);
if (enforced_gpo_dns[enforced_idx] == NULL) {
ret = ENOMEM;
goto done;
}
enforced_idx++;
} else {
unenforced_gpo_dns[unenforced_idx] =
talloc_steal(unenforced_gpo_dns, gp_gplink->gpo_dn);
if (unenforced_gpo_dns[unenforced_idx] == NULL) {
ret = ENOMEM;
goto done;
}
unenforced_idx++;
}
j++;
}
i++;
}
enforced_gpo_dns[num_enforced] = NULL;
unenforced_gpo_dns[num_unenforced] = NULL;
candidate_gpos = talloc_array(tmp_ctx,
struct gp_gpo *,
num_candidate_gpos + 1);
if (candidate_gpos == NULL) {
ret = ENOMEM;
goto done;
}
gpo_dn_idx = 0;
for (i = num_unenforced - 1; i >= 0; i--) {
candidate_gpos[gpo_dn_idx] = talloc_zero(candidate_gpos, struct gp_gpo);
if (candidate_gpos[gpo_dn_idx] == NULL) {
ret = ENOMEM;
goto done;
}
candidate_gpos[gpo_dn_idx]->gpo_dn =
talloc_steal(candidate_gpos[gpo_dn_idx], unenforced_gpo_dns[i]);
if (candidate_gpos[gpo_dn_idx]->gpo_dn == NULL) {
ret = ENOMEM;
goto done;
}
DEBUG(SSSDBG_TRACE_FUNC,
"candidate_gpos[%d]->gpo_dn: %s\n",
gpo_dn_idx, candidate_gpos[gpo_dn_idx]->gpo_dn);
gpo_dn_idx++;
}
for (i = 0; i < num_enforced; i++) {
candidate_gpos[gpo_dn_idx] = talloc_zero(candidate_gpos, struct gp_gpo);
if (candidate_gpos[gpo_dn_idx] == NULL) {
ret = ENOMEM;
goto done;
}
candidate_gpos[gpo_dn_idx]->gpo_dn =
talloc_steal(candidate_gpos[gpo_dn_idx], enforced_gpo_dns[i]);
if (candidate_gpos[gpo_dn_idx]->gpo_dn == NULL) {
ret = ENOMEM;
goto done;
}
DEBUG(SSSDBG_TRACE_FUNC,
"candidate_gpos[%d]->gpo_dn: %s\n",
gpo_dn_idx, candidate_gpos[gpo_dn_idx]->gpo_dn);
gpo_dn_idx++;
}
candidate_gpos[gpo_dn_idx] = NULL;
*_candidate_gpos = talloc_steal(mem_ctx, candidate_gpos);
*_num_candidate_gpos = num_candidate_gpos;
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
/*
* This function parses the input_path into its components, replaces each
* back slash ('\') with a forward slash ('/'), and populates the output params.
*
* The smb_server output is constructed by concatenating the following elements:
* - SMB_STANDARD_URI ("smb://")
* - server_hostname (which replaces domain_name in input path)
* The smb_share and smb_path outputs are extracted from the input_path.
*
* Example: if input_path = "\\foo.com\SysVol\foo.com\..." and
* server_hostname = "adserver.foo.com", then
* _smb_server = "smb://adserver.foo.com"
* _smb_share = "SysVol"
* _smb_path = "/foo.com/..."
*
* Note that the input_path must have at least four forward slash separators.
* For example, input_path = "\\foo.com\SysVol" is not a valid input_path,
* because it has only three forward slash separators.
*/
static errno_t
ad_gpo_extract_smb_components(TALLOC_CTX *mem_ctx,
char *server_hostname,
char *input_path,
const char **_smb_server,
const char **_smb_share,
const char **_smb_path)
{
char *ptr;
const char delim = '\\';
int ret;
int num_seps = 0;
char *smb_path = NULL;
char *smb_share = NULL;
DEBUG(SSSDBG_TRACE_ALL, "input_path: %s\n", input_path);
if (input_path == NULL ||
*input_path == '\0' ||
_smb_server == NULL ||
_smb_share == NULL ||
_smb_path == NULL) {
ret = EINVAL;
goto done;
}
ptr = input_path;
while ((ptr = strchr(ptr, delim))) {
num_seps++;
if (num_seps == 3) {
/* replace the slash before the share name with null string */
*ptr = '\0';
ptr++;
smb_share = ptr;
continue;
} else if (num_seps == 4) {
/* replace the slash after the share name with null string */
*ptr = '\0';
ptr++;
smb_path = ptr;
continue;
}
*ptr = '/';
ptr++;
}
if (num_seps == 0) {
ret = EINVAL;
goto done;
}
if (smb_path == NULL) {
ret = EINVAL;
goto done;
}
*_smb_server = talloc_asprintf(mem_ctx, "%s%s",
SMB_STANDARD_URI,
server_hostname);
if (*_smb_server == NULL) {
ret = ENOMEM;
goto done;
}
*_smb_share = talloc_asprintf(mem_ctx, "/%s", smb_share);
if (*_smb_share == NULL) {
ret = ENOMEM;
goto done;
}
*_smb_path = talloc_asprintf(mem_ctx, "/%s", smb_path);
if (*_smb_path == NULL) {
ret = ENOMEM;
goto done;
}
ret = EOK;
done:
return ret;
}
/*
* This function populates the _cse_guid_list output parameter by parsing the
* input raw_machine_ext_names_value into an array of cse_guid strings.
*
* The raw_machine_ext_names_value is a single string in the following format:
* "[{cse_guid_1}{tool_guid1}]...[{cse_guid_n}{tool_guid_n}]"
*/
static errno_t
ad_gpo_parse_machine_ext_names(TALLOC_CTX *mem_ctx,
char *raw_machine_ext_names_value,
const char ***_gpo_cse_guids,
int *_num_gpo_cse_guids)
{
TALLOC_CTX *tmp_ctx = NULL;
char *ptr;
char *first;
char *last;
char *cse_guid;
char *tool_guid;
const char delim = ']';
const char **gpo_cse_guids;
int i;
int ret;
int num_gpo_cse_guids = 0;
if (raw_machine_ext_names_value == NULL ||
*raw_machine_ext_names_value == '\0' ||
_gpo_cse_guids == NULL) {
return EINVAL;
}
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
ret = ENOMEM;
goto done;
}
ptr = raw_machine_ext_names_value;
while ((ptr = strchr(ptr, delim))) {
ptr++;
num_gpo_cse_guids++;
}
if (num_gpo_cse_guids == 0) {
ret = EINVAL;
goto done;
}
gpo_cse_guids = talloc_array(tmp_ctx, const char *, num_gpo_cse_guids + 1);
if (gpo_cse_guids == NULL) {
ret = ENOMEM;
goto done;
}
ptr = raw_machine_ext_names_value;
for (i = 0; i < num_gpo_cse_guids; i++) {
first = ptr + 1;
last = strchr(first, delim);
if (last == NULL) {
break;
}
*last = '\0';
last++;
cse_guid = first;
first ++;
tool_guid = strchr(first, '{');
if (tool_guid == NULL) {
break;
}
*tool_guid = '\0';
gpo_cse_guids[i] = talloc_strdup(gpo_cse_guids, cse_guid);
ptr = last;
}
gpo_cse_guids[i] = NULL;
DEBUG(SSSDBG_TRACE_ALL, "num_gpo_cse_guids: %d\n", num_gpo_cse_guids);
for (i = 0; i < num_gpo_cse_guids; i++) {
DEBUG(SSSDBG_TRACE_ALL,
"gpo_cse_guids[%d] is %s\n", i, gpo_cse_guids[i]);
}
*_gpo_cse_guids = talloc_steal(mem_ctx, gpo_cse_guids);
*_num_gpo_cse_guids = num_gpo_cse_guids;
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
enum ndr_err_code
ad_gpo_ndr_pull_security_descriptor(struct ndr_pull *ndr, int ndr_flags,
struct security_descriptor *r);
/*
* This function parses the input data blob and assigns the resulting
* security_descriptor object to the _gpo_sd output parameter.
*/
static errno_t ad_gpo_parse_sd(TALLOC_CTX *mem_ctx,
uint8_t *data,
size_t length,
struct security_descriptor **_gpo_sd)
{
struct ndr_pull *ndr_pull = NULL;
struct security_descriptor sd;
DATA_BLOB blob;
enum ndr_err_code ndr_err;
blob.data = data;
blob.length = length;
ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
if (ndr_pull == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_init_blob() failed.\n");
return EINVAL;
}
ndr_err = ad_gpo_ndr_pull_security_descriptor(ndr_pull,
NDR_SCALARS|NDR_BUFFERS,
&sd);
if (ndr_err != NDR_ERR_SUCCESS) {
DEBUG(SSSDBG_CRIT_FAILURE, "Failed to pull security descriptor\n");
return EINVAL;
}
*_gpo_sd = talloc_memdup(mem_ctx, &sd, sizeof(struct security_descriptor));
return EOK;
}
/* == ad_gpo_process_gpo_send/recv implementation ========================== */
struct ad_gpo_process_gpo_state {
struct tevent_context *ev;
struct sdap_id_op *sdap_op;
struct sdap_options *opts;
char *server_hostname;
int timeout;
struct gp_gpo **candidate_gpos;
int num_candidate_gpos;
int gpo_index;
};
static errno_t ad_gpo_get_gpo_attrs_step(struct tevent_req *req);
static void ad_gpo_get_gpo_attrs_done(struct tevent_req *subreq);
/*
* This function uses the input som_list to populate a prioritized list of
* gp_gpo objects, prioritized based on SOM type, link order, and whether the
* GPO is "enforced". This list represents the initial set of candidate GPOs
* that might be applicable to the target. This list can not be expanded, but
* it might be reduced based on subsequent filtering steps. The GPO object DNs
* are used to retrieve certain LDAP attributes of each GPO object, that are
* parsed into the various fields of the gp_gpo object.
*/
struct tevent_req *
ad_gpo_process_gpo_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct sdap_id_op *sdap_op,
struct sdap_options *opts,
char *server_hostname,
int timeout,
struct gp_som **som_list)
{
struct tevent_req *req;
struct ad_gpo_process_gpo_state *state;
errno_t ret;
req = tevent_req_create(mem_ctx, &state, struct ad_gpo_process_gpo_state);
if (req == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
return NULL;
}
state->ev = ev;
state->sdap_op = sdap_op;
state->opts = opts;
state->server_hostname = server_hostname;
state->timeout = timeout;
state->gpo_index = 0;
state->candidate_gpos = NULL;
state->num_candidate_gpos = 0;
ret = ad_gpo_populate_candidate_gpos(state,
som_list,
&state->candidate_gpos,
&state->num_candidate_gpos);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Unable to retrieve GPO List: [%d](%s)\n",
ret, sss_strerror(ret));
ret = ENOENT;
goto immediately;
}
if (state->candidate_gpos == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "no gpos found\n");
ret = ENOENT;
goto immediately;
}
ret = ad_gpo_get_gpo_attrs_step(req);
immediately:
if (ret == EOK) {
tevent_req_done(req);
tevent_req_post(req, ev);
} else if (ret != EAGAIN) {
tevent_req_error(req, ret);
tevent_req_post(req, ev);
}
return req;
}
static errno_t
ad_gpo_get_gpo_attrs_step(struct tevent_req *req)
{
const char *attrs[] = {AD_AT_NT_SEC_DESC, AD_AT_CN, AD_AT_FILE_SYS_PATH,
AD_AT_MACHINE_EXT_NAMES, AD_AT_FUNC_VERSION,
AD_AT_FLAGS, NULL};
struct tevent_req *subreq;
struct ad_gpo_process_gpo_state *state;
state = tevent_req_data(req, struct ad_gpo_process_gpo_state);
struct gp_gpo *gp_gpo = state->candidate_gpos[state->gpo_index];
/* gp_gpo is NULL only after all GPOs have been processed */
if (gp_gpo == NULL) return EOK;
const char *gpo_dn = gp_gpo->gpo_dn;
subreq = sdap_sd_search_send(state, state->ev,
state->opts, sdap_id_op_handle(state->sdap_op),
gpo_dn, SECINFO_DACL, attrs, state->timeout);
if (subreq == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
return ENOMEM;
}
tevent_req_set_callback(subreq, ad_gpo_get_gpo_attrs_done, req);
return EAGAIN;
}
static void
ad_gpo_get_gpo_attrs_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct ad_gpo_process_gpo_state *state;
int ret;
int dp_error;
size_t num_results;
struct sysdb_attrs **results;
struct ldb_message_element *el = NULL;
const char *gpo_guid = NULL;
const char *raw_file_sys_path = NULL;
char *file_sys_path = NULL;
uint8_t *raw_machine_ext_names = NULL;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct ad_gpo_process_gpo_state);
ret = sdap_sd_search_recv(subreq, state, &num_results, &results);
talloc_zfree(subreq);
if (ret != EOK) {
ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
DEBUG(SSSDBG_OP_FAILURE,
"Unable to get GPO attributes: [%d](%s)\n",
ret, sss_strerror(ret));
ret = ENOENT;
goto done;
}
if ((num_results < 1) || (results == NULL)) {
DEBUG(SSSDBG_OP_FAILURE, "no attrs found for GPO; try next GPO.\n");
state->gpo_index++;
ret = ad_gpo_get_gpo_attrs_step(req);
goto done;
}
else if (num_results > 1) {
DEBUG(SSSDBG_OP_FAILURE, "Received multiple replies\n");
ret = ERR_INTERNAL;
goto done;
}
struct gp_gpo *gp_gpo = state->candidate_gpos[state->gpo_index];
/* retrieve AD_AT_CN */
ret = sysdb_attrs_get_string(results[0], AD_AT_CN, &gpo_guid);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"sysdb_attrs_get_string failed: [%d](%s)\n",
ret, sss_strerror(ret));
goto done;
}
gp_gpo->gpo_guid = talloc_steal(gp_gpo, gpo_guid);
if (gp_gpo->gpo_guid == NULL) {
ret = ENOMEM;
goto done;
}
DEBUG(SSSDBG_TRACE_ALL, "populating attrs for gpo_guid: %s\n",
gp_gpo->gpo_guid);
/* retrieve AD_AT_FILE_SYS_PATH */
ret = sysdb_attrs_get_string(results[0],
AD_AT_FILE_SYS_PATH,
&raw_file_sys_path);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"sysdb_attrs_get_string failed: [%d](%s)\n",
ret, sss_strerror(ret));
goto done;
}
file_sys_path = talloc_strdup(gp_gpo, raw_file_sys_path);
ret = ad_gpo_extract_smb_components(gp_gpo, state->server_hostname,
file_sys_path, &gp_gpo->smb_server,
&gp_gpo->smb_share, &gp_gpo->smb_path);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"unable to extract smb components from file_sys_path: [%d](%s)\n",
ret, sss_strerror(ret));
goto done;
}
DEBUG(SSSDBG_TRACE_ALL, "smb_server: %s\n", gp_gpo->smb_server);
DEBUG(SSSDBG_TRACE_ALL, "smb_share: %s\n", gp_gpo->smb_share);
DEBUG(SSSDBG_TRACE_ALL, "smb_path: %s\n", gp_gpo->smb_path);
/* retrieve AD_AT_FUNC_VERSION */
ret = sysdb_attrs_get_int32_t(results[0], AD_AT_FUNC_VERSION,
&gp_gpo->gpo_func_version);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"sysdb_attrs_get_int32_t failed: [%d](%s)\n",
ret, sss_strerror(ret));
goto done;
}
DEBUG(SSSDBG_TRACE_ALL, "gpo_func_version: %d\n",
gp_gpo->gpo_func_version);
/* retrieve AD_AT_FLAGS */
ret = sysdb_attrs_get_int32_t(results[0], AD_AT_FLAGS,
&gp_gpo->gpo_flags);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"sysdb_attrs_get_int32_t failed: [%d](%s)\n",
ret, sss_strerror(ret));
goto done;
}
DEBUG(SSSDBG_TRACE_ALL, "gpo_flags: %d\n", gp_gpo->gpo_flags);
/* retrieve AD_AT_NT_SEC_DESC */
ret = sysdb_attrs_get_el(results[0], AD_AT_NT_SEC_DESC, &el);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el() failed\n");
goto done;
}
if ((ret == ENOENT) || (el->num_values == 0)) {
DEBUG(SSSDBG_OP_FAILURE,
"nt_sec_desc attribute not found or has no value\n");
ret = ENOENT;
goto done;
}
ret = ad_gpo_parse_sd(gp_gpo, el[0].values[0].data, el[0].values[0].length,
&gp_gpo->gpo_sd);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "ad_gpo_parse_sd() failed\n");
goto done;
}
/* retrieve AD_AT_MACHINE_EXT_NAMES */
ret = sysdb_attrs_get_el(results[0], AD_AT_MACHINE_EXT_NAMES, &el);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el() failed\n");
goto done;
}
if ((ret == ENOENT) || (el->num_values == 0)) {
/*
* if gpo has no machine_ext_names (which is perfectly valid: it could
* have only user_ext_names, for example), we continue to next gpo
*/
DEBUG(SSSDBG_TRACE_ALL,
"machine_ext_names attribute not found or has no value\n");
state->gpo_index++;
} else {
raw_machine_ext_names = el[0].values[0].data;
ret = ad_gpo_parse_machine_ext_names(gp_gpo,
(char *)raw_machine_ext_names,
&gp_gpo->gpo_cse_guids,
&gp_gpo->num_gpo_cse_guids);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"ad_gpo_parse_machine_ext_names() failed\n");
goto done;
}
state->gpo_index++;
}
ret = ad_gpo_get_gpo_attrs_step(req);
done:
if (ret == EOK) {
tevent_req_done(req);
} else if (ret != EAGAIN) {
tevent_req_error(req, ret);
}
}
int
ad_gpo_process_gpo_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
struct gp_gpo ***candidate_gpos,
int *num_candidate_gpos)
{
struct ad_gpo_process_gpo_state *state =
tevent_req_data(req, struct ad_gpo_process_gpo_state);
TEVENT_REQ_RETURN_ON_ERROR(req);
*candidate_gpos = talloc_steal(mem_ctx, state->candidate_gpos);
*num_candidate_gpos = state->num_candidate_gpos;
return EOK;
}
/* == ad_gpo_process_cse_send/recv helpers ================================= */
static errno_t
create_cse_send_buffer(TALLOC_CTX *mem_ctx,
const char *smb_server,
const char *smb_share,
const char *smb_path,
const char *smb_cse_suffix,
int cached_gpt_version,
struct io_buffer **io_buf)
{
struct io_buffer *buf;
size_t rp;
int smb_server_length;
int smb_share_length;
int smb_path_length;
int smb_cse_suffix_length;
smb_server_length = strlen(smb_server);
smb_share_length = strlen(smb_share);
smb_path_length = strlen(smb_path);
smb_cse_suffix_length = strlen(smb_cse_suffix);
buf = talloc(mem_ctx, struct io_buffer);
if (buf == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
return ENOMEM;
}
buf->size = 5 * sizeof(uint32_t);
buf->size += smb_server_length + smb_share_length + smb_path_length +
smb_cse_suffix_length;
DEBUG(SSSDBG_TRACE_ALL, "buffer size: %zu\n", buf->size);
buf->data = talloc_size(buf, buf->size);
if (buf->data == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
talloc_free(buf);
return ENOMEM;
}
rp = 0;
/* cached_gpt_version */
SAFEALIGN_SET_UINT32(&buf->data[rp], cached_gpt_version, &rp);
/* smb_server */
SAFEALIGN_SET_UINT32(&buf->data[rp], smb_server_length, &rp);
safealign_memcpy(&buf->data[rp], smb_server, smb_server_length, &rp);
/* smb_share */
SAFEALIGN_SET_UINT32(&buf->data[rp], smb_share_length, &rp);
safealign_memcpy(&buf->data[rp], smb_share, smb_share_length, &rp);
/* smb_path */
SAFEALIGN_SET_UINT32(&buf->data[rp], smb_path_length, &rp);
safealign_memcpy(&buf->data[rp], smb_path, smb_path_length, &rp);
/* smb_cse_suffix */
SAFEALIGN_SET_UINT32(&buf->data[rp], smb_cse_suffix_length, &rp);
safealign_memcpy(&buf->data[rp], smb_cse_suffix, smb_cse_suffix_length, &rp);
*io_buf = buf;
return EOK;
}
static errno_t
ad_gpo_parse_gpo_child_response(uint8_t *buf,
ssize_t size,
uint32_t *_sysvol_gpt_version,
uint32_t *_result)
{
int ret;
size_t p = 0;
uint32_t sysvol_gpt_version;
uint32_t result;
/* sysvol_gpt_version */
SAFEALIGN_COPY_UINT32_CHECK(&sysvol_gpt_version, buf + p, size, &p);
/* operation result code */
SAFEALIGN_COPY_UINT32_CHECK(&result, buf + p, size, &p);
*_sysvol_gpt_version = sysvol_gpt_version;
*_result = result;
ret = EOK;
return ret;
}
/* == ad_gpo_process_cse_send/recv implementation ========================== */
struct ad_gpo_process_cse_state {
struct tevent_context *ev;
struct sss_domain_info *domain;
int gpo_timeout_option;
const char *gpo_guid;
const char *smb_path;
const char *smb_cse_suffix;
pid_t child_pid;
uint8_t *buf;
ssize_t len;
struct child_io_fds *io;
};
static errno_t gpo_fork_child(struct tevent_req *req);
static void gpo_cse_step(struct tevent_req *subreq);
static void gpo_cse_done(struct tevent_req *subreq);
/*
* This cse-specific function (GP_EXT_GUID_SECURITY) sends the input smb uri
* components and cached_gpt_version to the gpo child, which, in turn,
* will download the GPT.INI file and policy files (as needed) and store
* them in the GPO_CACHE directory. Note that if the send_to_child input is
* false, this function simply completes the request.
*/
struct tevent_req *
ad_gpo_process_cse_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
bool send_to_child,
struct sss_domain_info *domain,
const char *gpo_guid,
const char *smb_server,
const char *smb_share,
const char *smb_path,
const char *smb_cse_suffix,
int cached_gpt_version,
int gpo_timeout_option)
{
struct tevent_req *req;
struct tevent_req *subreq;
struct ad_gpo_process_cse_state *state;
struct io_buffer *buf = NULL;
errno_t ret;
req = tevent_req_create(mem_ctx, &state, struct ad_gpo_process_cse_state);
if (req == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
return NULL;
}
if (!send_to_child) {
/*
* if we don't need to talk to child (b/c cache timeout is still valid),
* we simply complete the request
*/
ret = EOK;
goto immediately;
}
state->ev = ev;
state->buf = NULL;
state->len = 0;
state->domain = domain;
state->gpo_timeout_option = gpo_timeout_option;
state->gpo_guid = gpo_guid;
state->smb_path = smb_path;
state->smb_cse_suffix = smb_cse_suffix;
state->io = talloc(state, struct child_io_fds);
if (state->io == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
ret = ENOMEM;
goto immediately;
}
state->io->write_to_child_fd = -1;
state->io->read_from_child_fd = -1;
talloc_set_destructor((void *) state->io, child_io_destructor);
/* prepare the data to pass to child */
ret = create_cse_send_buffer(state, smb_server, smb_share, smb_path,
smb_cse_suffix, cached_gpt_version, &buf);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "create_cse_send_buffer failed.\n");
goto immediately;
}
ret = gpo_fork_child(req);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "gpo_fork_child failed.\n");
goto immediately;
}
subreq = write_pipe_send(state, ev, buf->data, buf->size,
state->io->write_to_child_fd);
if (subreq == NULL) {
ret = ENOMEM;
goto immediately;
}
tevent_req_set_callback(subreq, gpo_cse_step, req);
return req;
immediately:
if (ret == EOK) {
tevent_req_done(req);
tevent_req_post(req, ev);
} else {
tevent_req_error(req, ret);
tevent_req_post(req, ev);
}
return req;
}
static void gpo_cse_step(struct tevent_req *subreq)
{
struct tevent_req *req;
struct ad_gpo_process_cse_state *state;
int ret;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct ad_gpo_process_cse_state);
ret = write_pipe_recv(subreq);
talloc_zfree(subreq);
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
close(state->io->write_to_child_fd);
state->io->write_to_child_fd = -1;
subreq = read_pipe_send(state, state->ev, state->io->read_from_child_fd);
if (subreq == NULL) {
tevent_req_error(req, ENOMEM);
return;
}
tevent_req_set_callback(subreq, gpo_cse_done, req);
}
static void gpo_cse_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct ad_gpo_process_cse_state *state;
uint32_t sysvol_gpt_version = -1;
uint32_t child_result;
time_t now;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct ad_gpo_process_cse_state);
int ret;
ret = read_pipe_recv(subreq, state, &state->buf, &state->len);
talloc_zfree(subreq);
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
close(state->io->read_from_child_fd);
state->io->read_from_child_fd = -1;
ret = ad_gpo_parse_gpo_child_response(state->buf, state->len,
&sysvol_gpt_version, &child_result);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"ad_gpo_parse_gpo_child_response failed: [%d][%s]\n",
ret, strerror(ret));
tevent_req_error(req, ret);
return;
} else if (child_result != 0){
DEBUG(SSSDBG_CRIT_FAILURE,
"Error in gpo_child: [%d][%s]\n",
child_result, strerror(child_result));
tevent_req_error(req, child_result);
return;
}
now = time(NULL);
DEBUG(SSSDBG_TRACE_FUNC, "sysvol_gpt_version: %d\n", sysvol_gpt_version);
ret = sysdb_gpo_store_gpo(state->domain, state->gpo_guid, sysvol_gpt_version,
state->gpo_timeout_option, now);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "Unable to store gpo cache entry: [%d](%s}\n",
ret, sss_strerror(ret));
tevent_req_error(req, ret);
return;
}
tevent_req_done(req);
return;
}
int ad_gpo_process_cse_recv(struct tevent_req *req)
{
TEVENT_REQ_RETURN_ON_ERROR(req);
return EOK;
}
static errno_t
gpo_fork_child(struct tevent_req *req)
{
int pipefd_to_child[2];
int pipefd_from_child[2];
pid_t pid;
int ret;
errno_t err;
struct ad_gpo_process_cse_state *state;
state = tevent_req_data(req, struct ad_gpo_process_cse_state);
ret = pipe(pipefd_from_child);
if (ret == -1) {
err = errno;
DEBUG(SSSDBG_CRIT_FAILURE,
"pipe failed [%d][%s].\n", errno, strerror(errno));
return err;
}
ret = pipe(pipefd_to_child);
if (ret == -1) {
err = errno;
DEBUG(SSSDBG_CRIT_FAILURE,
"pipe failed [%d][%s].\n", errno, strerror(errno));
return err;
}
pid = fork();
if (pid == 0) { /* child */
err = exec_child(state,
pipefd_to_child, pipefd_from_child,
GPO_CHILD, gpo_child_debug_fd);
DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec gpo_child: [%d][%s].\n",
err, strerror(err));
return err;
} else if (pid > 0) { /* parent */
state->child_pid = pid;
state->io->read_from_child_fd = pipefd_from_child[0];
close(pipefd_from_child[1]);
state->io->write_to_child_fd = pipefd_to_child[1];
close(pipefd_to_child[0]);
fd_nonblocking(state->io->read_from_child_fd);
fd_nonblocking(state->io->write_to_child_fd);
ret = child_handler_setup(state->ev, pid, NULL, NULL, NULL);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Could not set up child signal handler\n");
return ret;
}
} else { /* error */
err = errno;
DEBUG(SSSDBG_CRIT_FAILURE,
"fork failed [%d][%s].\n", errno, strerror(errno));
return err;
}
return EOK;
}