diff options
Diffstat (limited to 'nsswitch')
33 files changed, 2371 insertions, 1996 deletions
diff --git a/nsswitch/config.m4 b/nsswitch/config.m4 deleted file mode 100644 index 2c8fa17ad9..0000000000 --- a/nsswitch/config.m4 +++ /dev/null @@ -1,11 +0,0 @@ -AC_CHECK_HEADERS(nss.h nss_common.h ns_api.h ) - -case "$host_os" in - *linux*) - SMB_LIBRARY(nss_winbind, - [../nsswitch/winbind_nss_linux.o], - [LIBWINBIND-CLIENT]) - ;; - *) - ;; -esac diff --git a/nsswitch/config.mk b/nsswitch/config.mk deleted file mode 100644 index 9ad873bed1..0000000000 --- a/nsswitch/config.mk +++ /dev/null @@ -1,41 +0,0 @@ -[SUBSYSTEM::LIBWINBIND-CLIENT] -PRIVATE_DEPENDENCIES = SOCKET_WRAPPER - -LIBWINBIND-CLIENT_OBJ_FILES = $(nsswitchsrcdir)/wb_common.o -$(LIBWINBIND-CLIENT_OBJ_FILES): CFLAGS+=-DWINBINDD_SOCKET_DIR=\"$(winbindd_socket_dir)\" - -################################# -# Start BINARY nsstest -[BINARY::nsstest] -INSTALLDIR = BINDIR -PRIVATE_DEPENDENCIES = \ - LIBSAMBA-UTIL \ - LIBREPLACE_EXT \ - LIBSAMBA-HOSTCONFIG -# End BINARY nsstest -################################# - -nsstest_OBJ_FILES = $(nsswitchsrcdir)/nsstest.o - -################################# -# Start BINARY wbinfo -[BINARY::wbinfo] -INSTALLDIR = BINDIR -PRIVATE_DEPENDENCIES = \ - LIBSAMBA-UTIL \ - LIBREPLACE_EXT \ - LIBCLI_AUTH \ - LIBPOPT \ - POPT_SAMBA \ - LIBWINBIND-CLIENT \ - LIBWBCLIENT \ - LIBTEVENT \ - UTIL_TEVENT \ - LIBASYNC_REQ \ - UID_WRAPPER -# End BINARY nsstest -################################# - -wbinfo_OBJ_FILES = \ - $(nsswitchsrcdir)/wbinfo.o -$(wbinfo_OBJ_FILES): CFLAGS+=-DWINBINDD_SOCKET_DIR=\"$(winbindd_socket_dir)\" diff --git a/nsswitch/libwbclient/config.mk b/nsswitch/libwbclient/config.mk deleted file mode 100644 index ffdab159f8..0000000000 --- a/nsswitch/libwbclient/config.mk +++ /dev/null @@ -1,15 +0,0 @@ -[SUBSYSTEM::LIBWBCLIENT] -PUBLIC_DEPENDENCIES = LIBASYNC_REQ \ - LIBTEVENT \ - LIBTALLOC \ - UTIL_TEVENT - -LIBWBCLIENT_OBJ_FILES = $(addprefix $(libwbclientsrcdir)/, wbc_async.o \ - wbc_guid.o \ - wbc_idmap.o \ - wbclient.o \ - wbc_pam.o \ - wbc_pwd.o \ - wbc_sid.o \ - wbc_util.o \ - wb_reqtrans.o ) diff --git a/nsswitch/libwbclient/libwbclient.h b/nsswitch/libwbclient/libwbclient.h index 5a25cf462c..867eb4d7c8 100644 --- a/nsswitch/libwbclient/libwbclient.h +++ b/nsswitch/libwbclient/libwbclient.h @@ -31,12 +31,9 @@ #include "nsswitch/winbind_nss_config.h" #include "nsswitch/winbind_struct_protocol.h" -#include <talloc.h> - /* Public headers */ #include "wbclient.h" -#include "wbc_async.h" /* Private headers */ diff --git a/nsswitch/libwbclient/tests/wbclient.c b/nsswitch/libwbclient/tests/wbclient.c index 23fad63025..c6ee531481 100644 --- a/nsswitch/libwbclient/tests/wbclient.c +++ b/nsswitch/libwbclient/tests/wbclient.c @@ -1,7 +1,7 @@ /* Unix SMB/CIFS implementation. SMB torture tester - Copyright (C) Guenther Deschner 2009 + Copyright (C) Guenther Deschner 2009-2010 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,10 +17,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "includes.h" +#include "lib/replace/replace.h" +#include "libcli/util/ntstatus.h" +#include "libcli/util/werror.h" +#include "lib/util/data_blob.h" +#include "lib/util/time.h" #include "nsswitch/libwbclient/wbclient.h" #include "torture/smbtorture.h" #include "torture/winbind/proto.h" +#include "lib/util/util_net.h" +#include "lib/util/charset/charset.h" +#include "libcli/auth/libcli_auth.h" +#include "source4/param/param.h" +#include "lib/util/util.h" +#include "lib/crypto/arcfour.h" #define WBC_ERROR_EQUAL(x,y) (x == y) @@ -43,6 +53,16 @@ static bool test_wbc_ping(struct torture_context *tctx) return true; } +static bool test_wbc_pingdc(struct torture_context *tctx) +{ + torture_assert_wbc_equal(tctx, wbcPingDc("random_string", NULL), WBC_ERR_NOT_IMPLEMENTED, + "wbcPingDc failed"); + torture_assert_wbc_ok(tctx, wbcPingDc(NULL, NULL), + "wbcPingDc failed"); + + return true; +} + static bool test_wbc_library_details(struct torture_context *tctx) { struct wbcLibraryDetails *details; @@ -108,6 +128,7 @@ static bool test_wbc_sidtostring(struct torture_context *tctx) "wbcSidToString failed"); torture_assert_str_equal(tctx, sid_string, sid_string2, "sid strings differ"); + wbcFreeMemory(sid_string2); return true; } @@ -124,26 +145,26 @@ static bool test_wbc_guidtostring(struct torture_context *tctx) "wbcGuidToString failed"); torture_assert_str_equal(tctx, guid_string, guid_string2, "guid strings differ"); + wbcFreeMemory(guid_string2); return true; } static bool test_wbc_domain_info(struct torture_context *tctx) { - const char *domain_name = NULL; struct wbcDomainInfo *info; struct wbcInterfaceDetails *details; torture_assert_wbc_ok(tctx, wbcInterfaceDetails(&details), "wbcInterfaceDetails failed"); - - domain_name = talloc_strdup(tctx, details->netbios_domain); + torture_assert_wbc_ok( + tctx, wbcDomainInfo(details->netbios_domain, &info), + "wbcDomainInfo failed"); wbcFreeMemory(details); - torture_assert_wbc_ok(tctx, wbcDomainInfo(domain_name, &info), - "wbcDomainInfo failed"); torture_assert(tctx, info, "wbcDomainInfo returned NULL pointer"); + wbcFreeMemory(info); return true; } @@ -185,9 +206,19 @@ static bool test_wbc_users(struct torture_context *tctx) "wbcLookupSid expected WBC_SID_NAME_USER"); torture_assert(tctx, name, "wbcLookupSid returned no name"); + wbcFreeMemory(domain); + wbcFreeMemory(name); torture_assert_wbc_ok(tctx, wbcLookupUserSids(&sid, true, &num_sids, &sids), "wbcLookupUserSids failed"); + torture_assert_wbc_ok( + tctx, wbcGetDisplayName(&sid, &domain, &name, + &name_type), + "wbcGetDisplayName failed"); + wbcFreeMemory(domain); + wbcFreeMemory(name); + wbcFreeMemory(sids); } + wbcFreeMemory(users); return true; } @@ -225,6 +256,7 @@ static bool test_wbc_groups(struct torture_context *tctx) torture_assert(tctx, name, "wbcLookupSid returned no name"); } + wbcFreeMemory(groups); return true; } @@ -264,6 +296,7 @@ static bool test_wbc_trusts(struct torture_context *tctx) "wbcLookupSid returned no name"); */ } + wbcFreeMemory(domains); return true; } @@ -282,6 +315,7 @@ static bool test_wbc_lookupdc(struct torture_context *tctx) torture_assert_wbc_ok(tctx, wbcLookupDomainController(domain_name, 0, &dc_info), "wbcLookupDomainController failed"); + wbcFreeMemory(dc_info); return true; } @@ -300,16 +334,354 @@ static bool test_wbc_lookupdcex(struct torture_context *tctx) torture_assert_wbc_ok(tctx, wbcLookupDomainControllerEx(domain_name, NULL, NULL, 0, &dc_info), "wbcLookupDomainControllerEx failed"); + wbcFreeMemory(dc_info); + + return true; +} + +static bool test_wbc_resolve_winsbyname(struct torture_context *tctx) +{ + const char *name; + char *ip; + wbcErr ret; + + name = torture_setting_string(tctx, "host", NULL); + + ret = wbcResolveWinsByName(name, &ip); + + if (is_ipaddress(name)) { + torture_assert_wbc_equal(tctx, ret, WBC_ERR_DOMAIN_NOT_FOUND, "wbcResolveWinsByName failed"); + } else { + torture_assert_wbc_ok(tctx, ret, "wbcResolveWinsByName failed"); + } + + return true; +} + +static bool test_wbc_resolve_winsbyip(struct torture_context *tctx) +{ + const char *ip; + char *name; + wbcErr ret; + + ip = torture_setting_string(tctx, "host", NULL); + + ret = wbcResolveWinsByIP(ip, &name); + + torture_assert_wbc_ok(tctx, ret, "wbcResolveWinsByIP failed"); + + wbcFreeMemory(name); + + return true; +} + +static bool test_wbc_lookup_rids(struct torture_context *tctx) +{ + struct wbcDomainSid builtin; + uint32_t rids[2] = { 544, 545 }; + const char *domain_name, **names; + enum wbcSidType *types; + wbcErr ret; + + wbcStringToSid("S-1-5-32", &builtin); + + ret = wbcLookupRids(&builtin, 2, rids, &domain_name, &names, + &types); + torture_assert_wbc_ok(tctx, ret, "wbcLookupRids failed"); + + torture_assert_str_equal( + tctx, names[0], "Administrators", + "S-1-5-32-544 not mapped to 'Administrators'"); + torture_assert_str_equal( + tctx, names[1], "Users", "S-1-5-32-545 not mapped to 'Users'"); + + wbcFreeMemory((char *)domain_name); + wbcFreeMemory(names); + wbcFreeMemory(types); + + return true; +} + +static bool test_wbc_get_sidaliases(struct torture_context *tctx) +{ + struct wbcDomainSid builtin; + struct wbcDomainInfo *info; + struct wbcInterfaceDetails *details; + struct wbcDomainSid sids[2]; + uint32_t *rids; + uint32_t num_rids; + wbcErr ret; + + torture_assert_wbc_ok(tctx, wbcInterfaceDetails(&details), + "wbcInterfaceDetails failed"); + torture_assert_wbc_ok( + tctx, wbcDomainInfo(details->netbios_domain, &info), + "wbcDomainInfo failed"); + wbcFreeMemory(details); + + sids[0] = info->sid; + sids[0].sub_auths[sids[0].num_auths++] = 500; + sids[1] = info->sid; + sids[1].sub_auths[sids[1].num_auths++] = 512; + wbcFreeMemory(info); + + torture_assert_wbc_ok( + tctx, wbcStringToSid("S-1-5-32", &builtin), + "wbcStringToSid failed"); + + ret = wbcGetSidAliases(&builtin, sids, 2, &rids, &num_rids); + torture_assert_wbc_ok(tctx, ret, "wbcGetSidAliases failed"); + + wbcFreeMemory(rids); + + return true; +} + +static bool test_wbc_authenticate_user_int(struct torture_context *tctx, + const char *correct_password) +{ + struct wbcAuthUserParams params; + struct wbcAuthUserInfo *info = NULL; + struct wbcAuthErrorInfo *error = NULL; + wbcErr ret; + + ret = wbcAuthenticateUser(getenv("USERNAME"), correct_password); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS, + "wbcAuthenticateUser failed"); + + ZERO_STRUCT(params); + params.account_name = getenv("USERNAME"); + params.level = WBC_AUTH_USER_LEVEL_PLAIN; + params.password.plaintext = correct_password; + + ret = wbcAuthenticateUserEx(¶ms, &info, &error); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS, + "wbcAuthenticateUserEx failed"); + wbcFreeMemory(info); + info = NULL; + + wbcFreeMemory(error); + error = NULL; + + params.password.plaintext = "wrong"; + ret = wbcAuthenticateUserEx(¶ms, &info, &error); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_AUTH_ERROR, + "wbcAuthenticateUserEx succeeded where it " + "should have failed"); + wbcFreeMemory(info); + info = NULL; + + wbcFreeMemory(error); + error = NULL; + + return true; +} + +static bool test_wbc_authenticate_user(struct torture_context *tctx) +{ + return test_wbc_authenticate_user_int(tctx, getenv("PASSWORD")); +} + +static bool test_wbc_change_password(struct torture_context *tctx) +{ + wbcErr ret; + const char *oldpass = getenv("PASSWORD"); + const char *newpass = "Koo8irei"; + + struct samr_CryptPassword new_nt_password; + struct samr_CryptPassword new_lm_password; + struct samr_Password old_nt_hash_enc; + struct samr_Password old_lanman_hash_enc; + + uint8_t old_nt_hash[16]; + uint8_t old_lanman_hash[16]; + uint8_t new_nt_hash[16]; + uint8_t new_lanman_hash[16]; + + struct wbcChangePasswordParams params; + + if (oldpass == NULL) { + torture_skip(tctx, + "skipping wbcChangeUserPassword test as old password cannot be retrieved\n"); + } + + ZERO_STRUCT(params); + + E_md4hash(oldpass, old_nt_hash); + E_md4hash(newpass, new_nt_hash); + + if (lpcfg_client_lanman_auth(tctx->lp_ctx) && + E_deshash(newpass, new_lanman_hash) && + E_deshash(oldpass, old_lanman_hash)) { + + /* E_deshash returns false for 'long' passwords (> 14 + DOS chars). This allows us to match Win2k, which + does not store a LM hash for these passwords (which + would reduce the effective password length to 14) */ + + encode_pw_buffer(new_lm_password.data, newpass, STR_UNICODE); + arcfour_crypt(new_lm_password.data, old_nt_hash, 516); + E_old_pw_hash(new_nt_hash, old_lanman_hash, + old_lanman_hash_enc.hash); + + params.old_password.response.old_lm_hash_enc_length = + sizeof(old_lanman_hash_enc.hash); + params.old_password.response.old_lm_hash_enc_data = + old_lanman_hash_enc.hash; + params.new_password.response.lm_length = + sizeof(new_lm_password.data); + params.new_password.response.lm_data = + new_lm_password.data; + } else { + ZERO_STRUCT(new_lm_password); + ZERO_STRUCT(old_lanman_hash_enc); + } + + encode_pw_buffer(new_nt_password.data, newpass, STR_UNICODE); + + arcfour_crypt(new_nt_password.data, old_nt_hash, 516); + E_old_pw_hash(new_nt_hash, old_nt_hash, old_nt_hash_enc.hash); + + params.old_password.response.old_nt_hash_enc_length = + sizeof(old_nt_hash_enc.hash); + params.old_password.response.old_nt_hash_enc_data = + old_nt_hash_enc.hash; + params.new_password.response.nt_length = sizeof(new_nt_password.data); + params.new_password.response.nt_data = new_nt_password.data; + + params.level = WBC_CHANGE_PASSWORD_LEVEL_RESPONSE; + params.account_name = getenv("USERNAME"); + params.domain_name = "SAMBA-TEST"; + + ret = wbcChangeUserPasswordEx(¶ms, NULL, NULL, NULL); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS, + "wbcChangeUserPassword failed"); + + if (!test_wbc_authenticate_user_int(tctx, "Koo8irei")) { + return false; + } + + ret = wbcChangeUserPassword(getenv("USERNAME"), "Koo8irei", + getenv("PASSWORD")); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS, + "wbcChangeUserPassword failed"); + + return test_wbc_authenticate_user_int(tctx, getenv("PASSWORD")); +} + +static bool test_wbc_logon_user(struct torture_context *tctx) +{ + struct wbcLogonUserParams params; + struct wbcLogonUserInfo *info = NULL; + struct wbcAuthErrorInfo *error = NULL; + struct wbcUserPasswordPolicyInfo *policy = NULL; + struct wbcInterfaceDetails *iface; + struct wbcDomainSid sid; + enum wbcSidType sidtype; + char *sidstr; + wbcErr ret; + + ZERO_STRUCT(params); + + ret = wbcLogonUser(¶ms, &info, &error, &policy); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_INVALID_PARAM, + "wbcLogonUser succeeded where it should " + "have failed"); + + params.username = getenv("USERNAME"); + params.password = getenv("PASSWORD"); + + ret = wbcAddNamedBlob(¶ms.num_blobs, ¶ms.blobs, + "foo", 0, discard_const_p(uint8_t, "bar"), 4); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS, + "wbcAddNamedBlob failed"); + + ret = wbcLogonUser(¶ms, &info, &error, &policy); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS, + "wbcLogonUser failed"); + wbcFreeMemory(info); info = NULL; + wbcFreeMemory(error); error = NULL; + wbcFreeMemory(policy); policy = NULL; + + params.password = "wrong"; + + ret = wbcLogonUser(¶ms, &info, &error, &policy); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_AUTH_ERROR, + "wbcLogonUser should have failed with " + "WBC_ERR_AUTH_ERROR"); + wbcFreeMemory(info); info = NULL; + wbcFreeMemory(error); error = NULL; + wbcFreeMemory(policy); policy = NULL; + + ret = wbcAddNamedBlob(¶ms.num_blobs, ¶ms.blobs, + "membership_of", 0, + discard_const_p(uint8_t, "S-1-2-3-4"), + strlen("S-1-2-3-4")+1); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS, + "wbcAddNamedBlob failed"); + params.password = getenv("PASSWORD"); + ret = wbcLogonUser(¶ms, &info, &error, &policy); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_AUTH_ERROR, + "wbcLogonUser should have failed with " + "WBC_ERR_AUTH_ERROR"); + wbcFreeMemory(info); info = NULL; + wbcFreeMemory(error); error = NULL; + wbcFreeMemory(policy); policy = NULL; + wbcFreeMemory(params.blobs); + params.blobs = NULL; params.num_blobs = 0; + + ret = wbcInterfaceDetails(&iface); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS, + "wbcInterfaceDetails failed"); + + ret = wbcLookupName(iface->netbios_domain, getenv("USERNAME"), &sid, + &sidtype); + wbcFreeMemory(iface); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS, + "wbcLookupName failed"); + + ret = wbcSidToString(&sid, &sidstr); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS, + "wbcSidToString failed"); + + ret = wbcAddNamedBlob(¶ms.num_blobs, ¶ms.blobs, + "membership_of", 0, + (uint8_t *)sidstr, strlen(sidstr)+1); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS, + "wbcAddNamedBlob failed"); + wbcFreeMemory(sidstr); + params.password = getenv("PASSWORD"); + ret = wbcLogonUser(¶ms, &info, &error, &policy); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS, + "wbcLogonUser failed"); + wbcFreeMemory(info); info = NULL; + wbcFreeMemory(error); error = NULL; + wbcFreeMemory(policy); policy = NULL; + wbcFreeMemory(params.blobs); + params.blobs = NULL; params.num_blobs = 0; return true; } +static bool test_wbc_getgroups(struct torture_context *tctx) +{ + wbcErr ret; + uint32_t num_groups; + gid_t *groups; + + ret = wbcGetGroups(getenv("USERNAME"), &num_groups, &groups); + torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS, + "wbcGetGroups failed"); + wbcFreeMemory(groups); + return true; +} struct torture_suite *torture_wbclient(void) { - struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "WBCLIENT"); + struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "wbclient"); torture_suite_add_simple_test(suite, "wbcPing", test_wbc_ping); + torture_suite_add_simple_test(suite, "wbcPingDc", test_wbc_pingdc); torture_suite_add_simple_test(suite, "wbcLibraryDetails", test_wbc_library_details); torture_suite_add_simple_test(suite, "wbcInterfaceDetails", test_wbc_interface_details); torture_suite_add_simple_test(suite, "wbcSidTypeString", test_wbc_sidtypestring); @@ -321,6 +693,20 @@ struct torture_suite *torture_wbclient(void) torture_suite_add_simple_test(suite, "wbcListTrusts", test_wbc_trusts); torture_suite_add_simple_test(suite, "wbcLookupDomainController", test_wbc_lookupdc); torture_suite_add_simple_test(suite, "wbcLookupDomainControllerEx", test_wbc_lookupdcex); + torture_suite_add_simple_test(suite, "wbcResolveWinsByName", test_wbc_resolve_winsbyname); + torture_suite_add_simple_test(suite, "wbcResolveWinsByIP", test_wbc_resolve_winsbyip); + torture_suite_add_simple_test(suite, "wbcLookupRids", + test_wbc_lookup_rids); + torture_suite_add_simple_test(suite, "wbcGetSidAliases", + test_wbc_get_sidaliases); + torture_suite_add_simple_test(suite, "wbcAuthenticateUser", + test_wbc_authenticate_user); + torture_suite_add_simple_test(suite, "wbcLogonUser", + test_wbc_logon_user); + torture_suite_add_simple_test(suite, "wbcChangeUserPassword", + test_wbc_change_password); + torture_suite_add_simple_test(suite, "wbcGetGroups", + test_wbc_getgroups); return suite; } diff --git a/nsswitch/libwbclient/wbc_async.c b/nsswitch/libwbclient/wbc_async.c deleted file mode 100644 index bb95b91740..0000000000 --- a/nsswitch/libwbclient/wbc_async.c +++ /dev/null @@ -1,774 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Infrastructure for async winbind requests - Copyright (C) Volker Lendecke 2008 - - ** NOTE! The following LGPL license applies to the wbclient - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "replace.h" -#include "system/filesys.h" -#include "system/network.h" -#include <talloc.h> -#include <tevent.h> -#include "lib/async_req/async_sock.h" -#include "nsswitch/winbind_struct_protocol.h" -#include "nsswitch/libwbclient/wbclient.h" -#include "nsswitch/libwbclient/wbc_async.h" - -wbcErr map_wbc_err_from_errno(int error) -{ - switch(error) { - case EPERM: - case EACCES: - return WBC_ERR_AUTH_ERROR; - case ENOMEM: - return WBC_ERR_NO_MEMORY; - case EIO: - default: - return WBC_ERR_UNKNOWN_FAILURE; - } -} - -bool tevent_req_is_wbcerr(struct tevent_req *req, wbcErr *pwbc_err) -{ - enum tevent_req_state state; - uint64_t error; - if (!tevent_req_is_error(req, &state, &error)) { - *pwbc_err = WBC_ERR_SUCCESS; - return false; - } - - switch (state) { - case TEVENT_REQ_USER_ERROR: - *pwbc_err = error; - break; - case TEVENT_REQ_TIMED_OUT: - *pwbc_err = WBC_ERR_UNKNOWN_FAILURE; - break; - case TEVENT_REQ_NO_MEMORY: - *pwbc_err = WBC_ERR_NO_MEMORY; - break; - default: - *pwbc_err = WBC_ERR_UNKNOWN_FAILURE; - break; - } - return true; -} - -wbcErr tevent_req_simple_recv_wbcerr(struct tevent_req *req) -{ - wbcErr wbc_err; - - if (tevent_req_is_wbcerr(req, &wbc_err)) { - return wbc_err; - } - - return WBC_ERR_SUCCESS; -} - -struct wbc_debug_ops { - void (*debug)(void *context, enum wbcDebugLevel level, - const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0); - void *context; -}; - -struct wb_context { - struct tevent_queue *queue; - int fd; - bool is_priv; - const char *dir; - struct wbc_debug_ops debug_ops; -}; - -static int make_nonstd_fd(int fd) -{ - int i; - int sys_errno = 0; - int fds[3]; - int num_fds = 0; - - if (fd == -1) { - return -1; - } - while (fd < 3) { - fds[num_fds++] = fd; - fd = dup(fd); - if (fd == -1) { - sys_errno = errno; - break; - } - } - for (i=0; i<num_fds; i++) { - close(fds[i]); - } - if (fd == -1) { - errno = sys_errno; - } - return fd; -} - -/**************************************************************************** - Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available, - else - if SYSV use O_NDELAY - if BSD use FNDELAY - Set close on exec also. -****************************************************************************/ - -static int make_safe_fd(int fd) -{ - int result, flags; - int new_fd = make_nonstd_fd(fd); - - if (new_fd == -1) { - goto fail; - } - - /* Socket should be nonblocking. */ - -#ifdef O_NONBLOCK -#define FLAG_TO_SET O_NONBLOCK -#else -#ifdef SYSV -#define FLAG_TO_SET O_NDELAY -#else /* BSD */ -#define FLAG_TO_SET FNDELAY -#endif -#endif - - if ((flags = fcntl(new_fd, F_GETFL)) == -1) { - goto fail; - } - - flags |= FLAG_TO_SET; - if (fcntl(new_fd, F_SETFL, flags) == -1) { - goto fail; - } - -#undef FLAG_TO_SET - - /* Socket should be closed on exec() */ -#ifdef FD_CLOEXEC - result = flags = fcntl(new_fd, F_GETFD, 0); - if (flags >= 0) { - flags |= FD_CLOEXEC; - result = fcntl( new_fd, F_SETFD, flags ); - } - if (result < 0) { - goto fail; - } -#endif - return new_fd; - - fail: - if (new_fd != -1) { - int sys_errno = errno; - close(new_fd); - errno = sys_errno; - } - return -1; -} - -/* Just put a prototype to avoid moving the whole function around */ -static const char *winbindd_socket_dir(void); - -struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx, const char* dir) -{ - struct wb_context *result; - - result = talloc(mem_ctx, struct wb_context); - if (result == NULL) { - return NULL; - } - result->queue = tevent_queue_create(result, "wb_trans"); - if (result->queue == NULL) { - TALLOC_FREE(result); - return NULL; - } - result->fd = -1; - result->is_priv = false; - - if (dir != NULL) { - result->dir = talloc_strdup(result, dir); - } else { - result->dir = winbindd_socket_dir(); - } - if (result->dir == NULL) { - TALLOC_FREE(result); - return NULL; - } - return result; -} - -struct wb_connect_state { - int dummy; -}; - -static void wbc_connect_connected(struct tevent_req *subreq); - -static struct tevent_req *wb_connect_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct wb_context *wb_ctx, - const char *dir) -{ - struct tevent_req *result, *subreq; - struct wb_connect_state *state; - struct sockaddr_un sunaddr; - struct stat st; - char *path = NULL; - wbcErr wbc_err; - - result = tevent_req_create(mem_ctx, &state, struct wb_connect_state); - if (result == NULL) { - return NULL; - } - - if (wb_ctx->fd != -1) { - close(wb_ctx->fd); - wb_ctx->fd = -1; - } - - /* Check permissions on unix socket directory */ - - if (lstat(dir, &st) == -1) { - wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE; - goto post_status; - } - - if (!S_ISDIR(st.st_mode) || - (st.st_uid != 0 && st.st_uid != geteuid())) { - wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE; - goto post_status; - } - - /* Connect to socket */ - - path = talloc_asprintf(mem_ctx, "%s/%s", dir, - WINBINDD_SOCKET_NAME); - if (path == NULL) { - goto nomem; - } - - sunaddr.sun_family = AF_UNIX; - strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)); - TALLOC_FREE(path); - - /* If socket file doesn't exist, don't bother trying to connect - with retry. This is an attempt to make the system usable when - the winbindd daemon is not running. */ - - if ((lstat(sunaddr.sun_path, &st) == -1) - || !S_ISSOCK(st.st_mode) - || (st.st_uid != 0 && st.st_uid != geteuid())) { - wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE; - goto post_status; - } - - wb_ctx->fd = make_safe_fd(socket(AF_UNIX, SOCK_STREAM, 0)); - if (wb_ctx->fd == -1) { - wbc_err = map_wbc_err_from_errno(errno); - goto post_status; - } - - subreq = async_connect_send(mem_ctx, ev, wb_ctx->fd, - (struct sockaddr *)(void *)&sunaddr, - sizeof(sunaddr)); - if (subreq == NULL) { - goto nomem; - } - tevent_req_set_callback(subreq, wbc_connect_connected, result); - return result; - - post_status: - tevent_req_error(result, wbc_err); - return tevent_req_post(result, ev); - nomem: - TALLOC_FREE(result); - return NULL; -} - -static void wbc_connect_connected(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - int res, err; - - res = async_connect_recv(subreq, &err); - TALLOC_FREE(subreq); - if (res == -1) { - tevent_req_error(req, map_wbc_err_from_errno(err)); - return; - } - tevent_req_done(req); -} - -static wbcErr wb_connect_recv(struct tevent_req *req) -{ - return tevent_req_simple_recv_wbcerr(req); -} - -static const char *winbindd_socket_dir(void) -{ -#ifdef SOCKET_WRAPPER - const char *env_dir; - - env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR); - if (env_dir) { - return env_dir; - } -#endif - - return WINBINDD_SOCKET_DIR; -} - -struct wb_open_pipe_state { - struct wb_context *wb_ctx; - struct tevent_context *ev; - bool need_priv; - struct winbindd_request wb_req; -}; - -static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq); -static void wb_open_pipe_ping_done(struct tevent_req *subreq); -static void wb_open_pipe_getpriv_done(struct tevent_req *subreq); -static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq); - -static struct tevent_req *wb_open_pipe_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct wb_context *wb_ctx, - bool need_priv) -{ - struct tevent_req *result, *subreq; - struct wb_open_pipe_state *state; - - result = tevent_req_create(mem_ctx, &state, struct wb_open_pipe_state); - if (result == NULL) { - return NULL; - } - state->wb_ctx = wb_ctx; - state->ev = ev; - state->need_priv = need_priv; - - if (wb_ctx->fd != -1) { - close(wb_ctx->fd); - wb_ctx->fd = -1; - } - - subreq = wb_connect_send(state, ev, wb_ctx, wb_ctx->dir); - if (subreq == NULL) { - goto fail; - } - tevent_req_set_callback(subreq, wb_open_pipe_connect_nonpriv_done, - result); - return result; - - fail: - TALLOC_FREE(result); - return NULL; -} - -static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_open_pipe_state *state = tevent_req_data( - req, struct wb_open_pipe_state); - wbcErr wbc_err; - - wbc_err = wb_connect_recv(subreq); - TALLOC_FREE(subreq); - if (!WBC_ERROR_IS_OK(wbc_err)) { - state->wb_ctx->is_priv = true; - tevent_req_error(req, wbc_err); - return; - } - - ZERO_STRUCT(state->wb_req); - state->wb_req.cmd = WINBINDD_INTERFACE_VERSION; - state->wb_req.pid = getpid(); - - subreq = wb_simple_trans_send(state, state->ev, NULL, - state->wb_ctx->fd, &state->wb_req); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_open_pipe_ping_done, req); -} - -static void wb_open_pipe_ping_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_open_pipe_state *state = tevent_req_data( - req, struct wb_open_pipe_state); - struct winbindd_response *wb_resp; - int ret, err; - - ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err); - TALLOC_FREE(subreq); - if (ret == -1) { - tevent_req_error(req, map_wbc_err_from_errno(err)); - return; - } - - if (!state->need_priv) { - tevent_req_done(req); - return; - } - - state->wb_req.cmd = WINBINDD_PRIV_PIPE_DIR; - state->wb_req.pid = getpid(); - - subreq = wb_simple_trans_send(state, state->ev, NULL, - state->wb_ctx->fd, &state->wb_req); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_open_pipe_getpriv_done, req); -} - -static void wb_open_pipe_getpriv_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_open_pipe_state *state = tevent_req_data( - req, struct wb_open_pipe_state); - struct winbindd_response *wb_resp = NULL; - int ret, err; - - ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err); - TALLOC_FREE(subreq); - if (ret == -1) { - tevent_req_error(req, map_wbc_err_from_errno(err)); - return; - } - - close(state->wb_ctx->fd); - state->wb_ctx->fd = -1; - - subreq = wb_connect_send(state, state->ev, state->wb_ctx, - (char *)wb_resp->extra_data.data); - TALLOC_FREE(wb_resp); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_open_pipe_connect_priv_done, req); -} - -static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_open_pipe_state *state = tevent_req_data( - req, struct wb_open_pipe_state); - wbcErr wbc_err; - - wbc_err = wb_connect_recv(subreq); - TALLOC_FREE(subreq); - if (!WBC_ERROR_IS_OK(wbc_err)) { - tevent_req_error(req, wbc_err); - return; - } - state->wb_ctx->is_priv = true; - tevent_req_done(req); -} - -static wbcErr wb_open_pipe_recv(struct tevent_req *req) -{ - return tevent_req_simple_recv_wbcerr(req); -} - -struct wb_trans_state { - struct wb_trans_state *prev, *next; - struct wb_context *wb_ctx; - struct tevent_context *ev; - struct winbindd_request *wb_req; - struct winbindd_response *wb_resp; - bool need_priv; -}; - -static bool closed_fd(int fd) -{ - struct timeval tv; - fd_set r_fds; - int selret; - - if (fd < 0 || fd >= FD_SETSIZE) { - return true; - } - - FD_ZERO(&r_fds); - FD_SET(fd, &r_fds); - ZERO_STRUCT(tv); - - selret = select(fd+1, &r_fds, NULL, NULL, &tv); - if (selret == -1) { - return true; - } - if (selret == 0) { - return false; - } - return (FD_ISSET(fd, &r_fds)); -} - -static void wb_trans_trigger(struct tevent_req *req, void *private_data); -static void wb_trans_connect_done(struct tevent_req *subreq); -static void wb_trans_done(struct tevent_req *subreq); -static void wb_trans_retry_wait_done(struct tevent_req *subreq); - -struct tevent_req *wb_trans_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct wb_context *wb_ctx, bool need_priv, - struct winbindd_request *wb_req) -{ - struct tevent_req *req; - struct wb_trans_state *state; - - req = tevent_req_create(mem_ctx, &state, struct wb_trans_state); - if (req == NULL) { - return NULL; - } - state->wb_ctx = wb_ctx; - state->ev = ev; - state->wb_req = wb_req; - state->need_priv = need_priv; - - if (!tevent_queue_add(wb_ctx->queue, ev, req, wb_trans_trigger, - NULL)) { - tevent_req_nomem(NULL, req); - return tevent_req_post(req, ev); - } - return req; -} - -static void wb_trans_trigger(struct tevent_req *req, void *private_data) -{ - struct wb_trans_state *state = tevent_req_data( - req, struct wb_trans_state); - struct tevent_req *subreq; - - if ((state->wb_ctx->fd != -1) && closed_fd(state->wb_ctx->fd)) { - close(state->wb_ctx->fd); - state->wb_ctx->fd = -1; - } - - if ((state->wb_ctx->fd == -1) - || (state->need_priv && !state->wb_ctx->is_priv)) { - subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx, - state->need_priv); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_trans_connect_done, req); - return; - } - - state->wb_req->pid = getpid(); - - subreq = wb_simple_trans_send(state, state->ev, NULL, - state->wb_ctx->fd, state->wb_req); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_trans_done, req); -} - -static bool wb_trans_retry(struct tevent_req *req, - struct wb_trans_state *state, - wbcErr wbc_err) -{ - struct tevent_req *subreq; - - if (WBC_ERROR_IS_OK(wbc_err)) { - return false; - } - - if (wbc_err == WBC_ERR_WINBIND_NOT_AVAILABLE) { - /* - * Winbind not around or we can't connect to the pipe. Fail - * immediately. - */ - tevent_req_error(req, wbc_err); - return true; - } - - /* - * The transfer as such failed, retry after one second - */ - - if (state->wb_ctx->fd != -1) { - close(state->wb_ctx->fd); - state->wb_ctx->fd = -1; - } - - subreq = tevent_wakeup_send(state, state->ev, - tevent_timeval_current_ofs(1, 0)); - if (tevent_req_nomem(subreq, req)) { - return true; - } - tevent_req_set_callback(subreq, wb_trans_retry_wait_done, req); - return true; -} - -static void wb_trans_retry_wait_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_trans_state *state = tevent_req_data( - req, struct wb_trans_state); - bool ret; - - ret = tevent_wakeup_recv(subreq); - TALLOC_FREE(subreq); - if (!ret) { - tevent_req_error(req, WBC_ERR_UNKNOWN_FAILURE); - return; - } - - subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx, - state->need_priv); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_trans_connect_done, req); -} - -static void wb_trans_connect_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_trans_state *state = tevent_req_data( - req, struct wb_trans_state); - wbcErr wbc_err; - - wbc_err = wb_open_pipe_recv(subreq); - TALLOC_FREE(subreq); - - if (wb_trans_retry(req, state, wbc_err)) { - return; - } - - subreq = wb_simple_trans_send(state, state->ev, NULL, - state->wb_ctx->fd, state->wb_req); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, wb_trans_done, req); -} - -static void wb_trans_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct wb_trans_state *state = tevent_req_data( - req, struct wb_trans_state); - int ret, err; - - ret = wb_simple_trans_recv(subreq, state, &state->wb_resp, &err); - TALLOC_FREE(subreq); - if ((ret == -1) - && wb_trans_retry(req, state, map_wbc_err_from_errno(err))) { - return; - } - - tevent_req_done(req); -} - -wbcErr wb_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - struct winbindd_response **presponse) -{ - struct wb_trans_state *state = tevent_req_data( - req, struct wb_trans_state); - wbcErr wbc_err; - - if (tevent_req_is_wbcerr(req, &wbc_err)) { - return wbc_err; - } - - *presponse = talloc_move(mem_ctx, &state->wb_resp); - return WBC_ERR_SUCCESS; -} - -/******************************************************************** - * Debug wrapper functions, modeled (with lot's of code copied as is) - * after the tevent debug wrapper functions - ********************************************************************/ - -/* - this allows the user to choose their own debug function -*/ -int wbcSetDebug(struct wb_context *wb_ctx, - void (*debug)(void *context, - enum wbcDebugLevel level, - const char *fmt, - va_list ap) PRINTF_ATTRIBUTE(3,0), - void *context) -{ - wb_ctx->debug_ops.debug = debug; - wb_ctx->debug_ops.context = context; - return 0; -} - -/* - debug function for wbcSetDebugStderr -*/ -static void wbcDebugStderr(void *private_data, - enum wbcDebugLevel level, - const char *fmt, - va_list ap) PRINTF_ATTRIBUTE(3,0); -static void wbcDebugStderr(void *private_data, - enum wbcDebugLevel level, - const char *fmt, va_list ap) -{ - if (level <= WBC_DEBUG_WARNING) { - vfprintf(stderr, fmt, ap); - } -} - -/* - convenience function to setup debug messages on stderr - messages of level WBC_DEBUG_WARNING and higher are printed -*/ -int wbcSetDebugStderr(struct wb_context *wb_ctx) -{ - return wbcSetDebug(wb_ctx, wbcDebugStderr, wb_ctx); -} - -/* - * log a message - * - * The default debug action is to ignore debugging messages. - * This is the most appropriate action for a library. - * Applications using the library must decide where to - * redirect debugging messages -*/ -void wbcDebug(struct wb_context *wb_ctx, enum wbcDebugLevel level, - const char *fmt, ...) -{ - va_list ap; - if (!wb_ctx) { - return; - } - if (wb_ctx->debug_ops.debug == NULL) { - return; - } - va_start(ap, fmt); - wb_ctx->debug_ops.debug(wb_ctx->debug_ops.context, level, fmt, ap); - va_end(ap); -} diff --git a/nsswitch/libwbclient/wbc_guid.c b/nsswitch/libwbclient/wbc_guid.c index d55a197973..52a64ca580 100644 --- a/nsswitch/libwbclient/wbc_guid.c +++ b/nsswitch/libwbclient/wbc_guid.c @@ -29,28 +29,24 @@ wbcErr wbcGuidToString(const struct wbcGuid *guid, char **guid_string) { - wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + char *result; - if (!guid) { - wbc_status = WBC_ERR_INVALID_PARAM; - BAIL_ON_WBC_ERROR(wbc_status); + result = (char *)wbcAllocateMemory(37, 1, NULL); + if (result == NULL) { + return WBC_ERR_NO_MEMORY; } - - *guid_string = talloc_asprintf(NULL, - "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - guid->time_low, guid->time_mid, - guid->time_hi_and_version, - guid->clock_seq[0], - guid->clock_seq[1], - guid->node[0], guid->node[1], - guid->node[2], guid->node[3], - guid->node[4], guid->node[5]); - BAIL_ON_PTR_ERROR((*guid_string), wbc_status); - - wbc_status = WBC_ERR_SUCCESS; - -done: - return wbc_status; + snprintf(result, 37, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + guid->time_low, guid->time_mid, + guid->time_hi_and_version, + guid->clock_seq[0], + guid->clock_seq[1], + guid->node[0], guid->node[1], + guid->node[2], guid->node[3], + guid->node[4], guid->node[5]); + *guid_string = result; + + return WBC_ERR_SUCCESS; } /* @brief Convert a character string to a binary GUID */ diff --git a/nsswitch/libwbclient/wbc_idmap.c b/nsswitch/libwbclient/wbc_idmap.c index bde14411ab..ad3cfe6770 100644 --- a/nsswitch/libwbclient/wbc_idmap.c +++ b/nsswitch/libwbclient/wbc_idmap.c @@ -5,7 +5,6 @@ Copyright (C) Gerald (Jerry) Carter 2007 - This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either @@ -24,13 +23,13 @@ #include "replace.h" #include "libwbclient.h" +#include "../winbind_client.h" /* Convert a Windows SID to a Unix uid, allocating an uid if needed */ wbcErr wbcSidToUid(const struct wbcDomainSid *sid, uid_t *puid) { struct winbindd_request request; struct winbindd_response response; - char *sid_string = NULL; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; if (!sid || !puid) { @@ -43,11 +42,7 @@ wbcErr wbcSidToUid(const struct wbcDomainSid *sid, uid_t *puid) ZERO_STRUCT(request); ZERO_STRUCT(response); - wbc_status = wbcSidToString(sid, &sid_string); - BAIL_ON_WBC_ERROR(wbc_status); - - strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1); - wbcFreeMemory(sid_string); + wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid)); /* Make request */ @@ -125,7 +120,6 @@ wbcErr wbcSidToGid(const struct wbcDomainSid *sid, gid_t *pgid) struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; - char *sid_string = NULL; if (!sid || !pgid) { wbc_status = WBC_ERR_INVALID_PARAM; @@ -137,11 +131,7 @@ wbcErr wbcSidToGid(const struct wbcDomainSid *sid, gid_t *pgid) ZERO_STRUCT(request); ZERO_STRUCT(response); - wbc_status = wbcSidToString(sid, &sid_string); - BAIL_ON_WBC_ERROR(wbc_status); - - strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1); - wbcFreeMemory(sid_string); + wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid)); /* Make request */ @@ -158,6 +148,7 @@ wbcErr wbcSidToGid(const struct wbcDomainSid *sid, gid_t *pgid) return wbc_status; } + /* Convert a Windows SID to a Unix gid if there already is a mapping */ wbcErr wbcQuerySidToGid(const struct wbcDomainSid *sid, @@ -166,6 +157,7 @@ wbcErr wbcQuerySidToGid(const struct wbcDomainSid *sid, return WBC_ERR_NOT_IMPLEMENTED; } + /* Convert a Unix gid to a Windows SID, allocating a SID if needed */ wbcErr wbcGidToSid(gid_t gid, struct wbcDomainSid *sid) { @@ -270,200 +262,130 @@ wbcErr wbcAllocateGid(gid_t *pgid) #define _ID_TYPE_UID 1 #define _ID_TYPE_GID 2 -/* Set an user id mapping */ +/* Set an user id mapping - not implemented any more */ wbcErr wbcSetUidMapping(uid_t uid, const struct wbcDomainSid *sid) { - struct winbindd_request request; - struct winbindd_response response; - wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; - char *sid_string = NULL; - - if (!sid) { - return WBC_ERR_INVALID_PARAM; - } - - /* Initialise request */ - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Make request */ - - request.data.dual_idmapset.id = uid; - request.data.dual_idmapset.type = _ID_TYPE_UID; - - wbc_status = wbcSidToString(sid, &sid_string); - BAIL_ON_WBC_ERROR(wbc_status); - - strncpy(request.data.dual_idmapset.sid, sid_string, - sizeof(request.data.dual_idmapset.sid)-1); - wbcFreeMemory(sid_string); - - wbc_status = wbcRequestResponsePriv(WINBINDD_SET_MAPPING, - &request, &response); - BAIL_ON_WBC_ERROR(wbc_status); - - done: - return wbc_status; + return WBC_ERR_NOT_IMPLEMENTED; } -/* Set a group id mapping */ +/* Set a group id mapping - not implemented any more */ wbcErr wbcSetGidMapping(gid_t gid, const struct wbcDomainSid *sid) { - struct winbindd_request request; - struct winbindd_response response; - wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; - char *sid_string = NULL; - - if (!sid) { - return WBC_ERR_INVALID_PARAM; - } - - /* Initialise request */ - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Make request */ - - request.data.dual_idmapset.id = gid; - request.data.dual_idmapset.type = _ID_TYPE_GID; - - wbc_status = wbcSidToString(sid, &sid_string); - BAIL_ON_WBC_ERROR(wbc_status); - - strncpy(request.data.dual_idmapset.sid, sid_string, - sizeof(request.data.dual_idmapset.sid)-1); - wbcFreeMemory(sid_string); - - wbc_status = wbcRequestResponsePriv(WINBINDD_SET_MAPPING, - &request, &response); - BAIL_ON_WBC_ERROR(wbc_status); - - done: - return wbc_status; + return WBC_ERR_NOT_IMPLEMENTED; } -/* Remove a user id mapping */ +/* Remove a user id mapping - not implemented any more */ wbcErr wbcRemoveUidMapping(uid_t uid, const struct wbcDomainSid *sid) { - struct winbindd_request request; - struct winbindd_response response; - wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; - char *sid_string = NULL; - - if (!sid) { - return WBC_ERR_INVALID_PARAM; - } - - /* Initialise request */ - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Make request */ - - request.data.dual_idmapset.id = uid; - request.data.dual_idmapset.type = _ID_TYPE_UID; - - wbc_status = wbcSidToString(sid, &sid_string); - BAIL_ON_WBC_ERROR(wbc_status); - - strncpy(request.data.dual_idmapset.sid, sid_string, - sizeof(request.data.dual_idmapset.sid)-1); - wbcFreeMemory(sid_string); - - wbc_status = wbcRequestResponsePriv(WINBINDD_REMOVE_MAPPING, - &request, &response); - BAIL_ON_WBC_ERROR(wbc_status); - - done: - return wbc_status; + return WBC_ERR_NOT_IMPLEMENTED; } -/* Remove a group id mapping */ +/* Remove a group id mapping - not implemented any more */ wbcErr wbcRemoveGidMapping(gid_t gid, const struct wbcDomainSid *sid) { - struct winbindd_request request; - struct winbindd_response response; - wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; - char *sid_string = NULL; - - if (!sid) { - return WBC_ERR_INVALID_PARAM; - } - - /* Initialise request */ - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Make request */ - - request.data.dual_idmapset.id = gid; - request.data.dual_idmapset.type = _ID_TYPE_GID; - - wbc_status = wbcSidToString(sid, &sid_string); - BAIL_ON_WBC_ERROR(wbc_status); - - strncpy(request.data.dual_idmapset.sid, sid_string, - sizeof(request.data.dual_idmapset.sid)-1); - wbcFreeMemory(sid_string); + return WBC_ERR_NOT_IMPLEMENTED; +} - wbc_status = wbcRequestResponsePriv(WINBINDD_REMOVE_MAPPING, - &request, &response); - BAIL_ON_WBC_ERROR(wbc_status); +/* Set the highwater mark for allocated uids - not implemented any more */ +wbcErr wbcSetUidHwm(uid_t uid_hwm) +{ + return WBC_ERR_NOT_IMPLEMENTED; +} - done: - return wbc_status; +/* Set the highwater mark for allocated gids - not implemented any more */ +wbcErr wbcSetGidHwm(gid_t gid_hwm) +{ + return WBC_ERR_NOT_IMPLEMENTED; } -/* Set the highwater mark for allocated uids. */ -wbcErr wbcSetUidHwm(uid_t uid_hwm) +/* Convert a list of SIDs */ +wbcErr wbcSidsToUnixIds(const struct wbcDomainSid *sids, uint32_t num_sids, + struct wbcUnixId *ids) { struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + int buflen, extra_len; + uint32_t i; + char *sidlist, *p, *extra_data; - /* Initialise request */ + buflen = num_sids * (WBC_SID_STRING_BUFLEN + 1) + 1; - ZERO_STRUCT(request); - ZERO_STRUCT(response); + sidlist = (char *)malloc(buflen); + if (sidlist == NULL) { + return WBC_ERR_NO_MEMORY; + } - /* Make request */ + p = sidlist; - request.data.dual_idmapset.id = uid_hwm; - request.data.dual_idmapset.type = _ID_TYPE_UID; + for (i=0; i<num_sids; i++) { + int remaining; + int len; - wbc_status = wbcRequestResponsePriv(WINBINDD_SET_HWM, - &request, &response); - BAIL_ON_WBC_ERROR(wbc_status); + remaining = buflen - (p - sidlist); - done: - return wbc_status; -} + len = wbcSidToStringBuf(&sids[i], p, remaining); + if (len > remaining) { + free(sidlist); + return WBC_ERR_UNKNOWN_FAILURE; + } -/* Set the highwater mark for allocated gids. */ -wbcErr wbcSetGidHwm(gid_t gid_hwm) -{ - struct winbindd_request request; - struct winbindd_response response; - wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; - - /* Initialise request */ + p += len; + *p++ = '\n'; + } + *p++ = '\0'; ZERO_STRUCT(request); ZERO_STRUCT(response); - /* Make request */ + request.extra_data.data = sidlist; + request.extra_len = p - sidlist; - request.data.dual_idmapset.id = gid_hwm; - request.data.dual_idmapset.type = _ID_TYPE_GID; + wbc_status = wbcRequestResponse(WINBINDD_SIDS_TO_XIDS, + &request, &response); + free(sidlist); + if (!WBC_ERROR_IS_OK(wbc_status)) { + return wbc_status; + } - wbc_status = wbcRequestResponsePriv(WINBINDD_SET_HWM, - &request, &response); - BAIL_ON_WBC_ERROR(wbc_status); + extra_len = response.length - sizeof(struct winbindd_response); + extra_data = (char *)response.extra_data.data; - done: + if ((extra_len <= 0) || (extra_data[extra_len-1] != '\0')) { + goto wbc_err_invalid; + } + + p = extra_data; + + for (i=0; i<num_sids; i++) { + struct wbcUnixId *id = &ids[i]; + char *q; + + switch (p[0]) { + case 'U': + id->type = WBC_ID_TYPE_UID; + id->id.uid = strtoul(p+1, &q, 10); + break; + case 'G': + id->type = WBC_ID_TYPE_GID; + id->id.gid = strtoul(p+1, &q, 10); + break; + default: + id->type = WBC_ID_TYPE_NOT_SPECIFIED; + q = p; + break; + }; + if (q[0] != '\n') { + goto wbc_err_invalid; + } + p = q+1; + } + wbc_status = WBC_ERR_SUCCESS; + goto done; + +wbc_err_invalid: + wbc_status = WBC_ERR_INVALID_RESPONSE; +done: + winbindd_free_response(&response); return wbc_status; } diff --git a/nsswitch/libwbclient/wbc_pam.c b/nsswitch/libwbclient/wbc_pam.c index 8c725d2fca..21f2c5d050 100644 --- a/nsswitch/libwbclient/wbc_pam.c +++ b/nsswitch/libwbclient/wbc_pam.c @@ -25,6 +25,7 @@ #include "replace.h" #include "libwbclient.h" +#include "../winbind_client.h" /* Authenticate a username/password pair */ wbcErr wbcAuthenticateUser(const char *username, @@ -46,8 +47,36 @@ done: return wbc_status; } -static wbcErr wbc_create_auth_info(TALLOC_CTX *mem_ctx, - const struct winbindd_response *resp, +static bool sid_attr_compose(struct wbcSidWithAttr *s, + const struct wbcDomainSid *d, + uint32_t rid, uint32_t attr) +{ + if (d->num_auths >= WBC_MAXSUBAUTHS) { + return false; + } + s->sid = *d; + s->sid.sub_auths[s->sid.num_auths++] = rid; + s->attributes = attr; + return true; +} + +static void wbcAuthUserInfoDestructor(void *ptr) +{ + struct wbcAuthUserInfo *i = (struct wbcAuthUserInfo *)ptr; + free(i->account_name); + free(i->user_principal); + free(i->full_name); + free(i->domain_name); + free(i->dns_domain_name); + free(i->logon_server); + free(i->logon_script); + free(i->profile_path); + free(i->home_directory); + free(i->home_drive); + free(i->sids); +} + +static wbcErr wbc_create_auth_info(const struct winbindd_response *resp, struct wbcAuthUserInfo **_i) { wbcErr wbc_status = WBC_ERR_SUCCESS; @@ -57,17 +86,19 @@ static wbcErr wbc_create_auth_info(TALLOC_CTX *mem_ctx, uint32_t sn = 0; uint32_t j; - i = talloc(mem_ctx, struct wbcAuthUserInfo); + i = (struct wbcAuthUserInfo *)wbcAllocateMemory( + 1, sizeof(struct wbcAuthUserInfo), + wbcAuthUserInfoDestructor); BAIL_ON_PTR_ERROR(i, wbc_status); i->user_flags = resp->data.auth.info3.user_flgs; - i->account_name = talloc_strdup(i, resp->data.auth.info3.user_name); + i->account_name = strdup(resp->data.auth.info3.user_name); BAIL_ON_PTR_ERROR(i->account_name, wbc_status); i->user_principal= NULL; - i->full_name = talloc_strdup(i, resp->data.auth.info3.full_name); + i->full_name = strdup(resp->data.auth.info3.full_name); BAIL_ON_PTR_ERROR(i->full_name, wbc_status); - i->domain_name = talloc_strdup(i, resp->data.auth.info3.logon_dom); + i->domain_name = strdup(resp->data.auth.info3.logon_dom); BAIL_ON_PTR_ERROR(i->domain_name, wbc_status); i->dns_domain_name= NULL; @@ -89,47 +120,41 @@ static wbcErr wbc_create_auth_info(TALLOC_CTX *mem_ctx, i->pass_can_change_time = resp->data.auth.info3.pass_can_change_time; i->pass_must_change_time= resp->data.auth.info3.pass_must_change_time; - i->logon_server = talloc_strdup(i, resp->data.auth.info3.logon_srv); + i->logon_server = strdup(resp->data.auth.info3.logon_srv); BAIL_ON_PTR_ERROR(i->logon_server, wbc_status); - i->logon_script = talloc_strdup(i, resp->data.auth.info3.logon_script); + i->logon_script = strdup(resp->data.auth.info3.logon_script); BAIL_ON_PTR_ERROR(i->logon_script, wbc_status); - i->profile_path = talloc_strdup(i, resp->data.auth.info3.profile_path); + i->profile_path = strdup(resp->data.auth.info3.profile_path); BAIL_ON_PTR_ERROR(i->profile_path, wbc_status); - i->home_directory= talloc_strdup(i, resp->data.auth.info3.home_dir); + i->home_directory= strdup(resp->data.auth.info3.home_dir); BAIL_ON_PTR_ERROR(i->home_directory, wbc_status); - i->home_drive = talloc_strdup(i, resp->data.auth.info3.dir_drive); + i->home_drive = strdup(resp->data.auth.info3.dir_drive); BAIL_ON_PTR_ERROR(i->home_drive, wbc_status); i->num_sids = 2; i->num_sids += resp->data.auth.info3.num_groups; i->num_sids += resp->data.auth.info3.num_other_sids; - i->sids = talloc_array(i, struct wbcSidWithAttr, i->num_sids); + i->sids = (struct wbcSidWithAttr *)calloc( + sizeof(struct wbcSidWithAttr), i->num_sids); BAIL_ON_PTR_ERROR(i->sids, wbc_status); wbc_status = wbcStringToSid(resp->data.auth.info3.dom_sid, &domain_sid); BAIL_ON_WBC_ERROR(wbc_status); -#define _SID_COMPOSE(s, d, r, a) { \ - (s).sid = d; \ - if ((s).sid.num_auths < WBC_MAXSUBAUTHS) { \ - (s).sid.sub_auths[(s).sid.num_auths++] = r; \ - } else { \ - wbc_status = WBC_ERR_INVALID_SID; \ - BAIL_ON_WBC_ERROR(wbc_status); \ - } \ - (s).attributes = a; \ -} while (0) - sn = 0; - _SID_COMPOSE(i->sids[sn], domain_sid, - resp->data.auth.info3.user_rid, - 0); + if (!sid_attr_compose(&i->sids[sn], &domain_sid, + resp->data.auth.info3.user_rid, 0)) { + wbc_status = WBC_ERR_INVALID_SID; + goto done; + } sn++; - _SID_COMPOSE(i->sids[sn], domain_sid, - resp->data.auth.info3.group_rid, - 0); + if (!sid_attr_compose(&i->sids[sn], &domain_sid, + resp->data.auth.info3.group_rid, 0)) { + wbc_status = WBC_ERR_INVALID_SID; + goto done; + } sn++; p = (char *)resp->extra_data.data; @@ -157,8 +182,11 @@ static wbcErr wbc_create_auth_info(TALLOC_CTX *mem_ctx, BAIL_ON_WBC_ERROR(wbc_status); } - _SID_COMPOSE(i->sids[sn], domain_sid, - rid, attrs); + if (!sid_attr_compose(&i->sids[sn], &domain_sid, + rid, attrs)) { + wbc_status = WBC_ERR_INVALID_SID; + goto done; + } sn++; } @@ -202,44 +230,52 @@ static wbcErr wbc_create_auth_info(TALLOC_CTX *mem_ctx, *_i = i; i = NULL; done: - talloc_free(i); + wbcFreeMemory(i); return wbc_status; } -static wbcErr wbc_create_error_info(TALLOC_CTX *mem_ctx, - const struct winbindd_response *resp, - struct wbcAuthErrorInfo **_e) +static void wbcAuthErrorInfoDestructor(void *ptr) +{ + struct wbcAuthErrorInfo *e = (struct wbcAuthErrorInfo *)ptr; + free(e->nt_string); + free(e->display_string); +} + +static wbcErr wbc_create_error_info(const struct winbindd_response *resp, + struct wbcAuthErrorInfo **_e) { wbcErr wbc_status = WBC_ERR_SUCCESS; struct wbcAuthErrorInfo *e; - e = talloc(mem_ctx, struct wbcAuthErrorInfo); + e = (struct wbcAuthErrorInfo *)wbcAllocateMemory( + 1, sizeof(struct wbcAuthErrorInfo), + wbcAuthErrorInfoDestructor); BAIL_ON_PTR_ERROR(e, wbc_status); e->nt_status = resp->data.auth.nt_status; e->pam_error = resp->data.auth.pam_error; - e->nt_string = talloc_strdup(e, resp->data.auth.nt_status_string); + e->nt_string = strdup(resp->data.auth.nt_status_string); BAIL_ON_PTR_ERROR(e->nt_string, wbc_status); - e->display_string = talloc_strdup(e, resp->data.auth.error_string); + e->display_string = strdup(resp->data.auth.error_string); BAIL_ON_PTR_ERROR(e->display_string, wbc_status); *_e = e; e = NULL; done: - talloc_free(e); + wbcFreeMemory(e); return wbc_status; } -static wbcErr wbc_create_password_policy_info(TALLOC_CTX *mem_ctx, - const struct winbindd_response *resp, +static wbcErr wbc_create_password_policy_info(const struct winbindd_response *resp, struct wbcUserPasswordPolicyInfo **_i) { wbcErr wbc_status = WBC_ERR_SUCCESS; struct wbcUserPasswordPolicyInfo *i; - i = talloc(mem_ctx, struct wbcUserPasswordPolicyInfo); + i = (struct wbcUserPasswordPolicyInfo *)wbcAllocateMemory( + 1, sizeof(struct wbcUserPasswordPolicyInfo), NULL); BAIL_ON_PTR_ERROR(i, wbc_status); i->min_passwordage = resp->data.auth.policy.min_passwordage; @@ -252,25 +288,32 @@ static wbcErr wbc_create_password_policy_info(TALLOC_CTX *mem_ctx, i = NULL; done: - talloc_free(i); + wbcFreeMemory(i); return wbc_status; } -static wbcErr wbc_create_logon_info(TALLOC_CTX *mem_ctx, - struct winbindd_response *resp, +static void wbcLogonUserInfoDestructor(void *ptr) +{ + struct wbcLogonUserInfo *i = (struct wbcLogonUserInfo *)ptr; + wbcFreeMemory(i->info); + wbcFreeMemory(i->blobs); +} + +static wbcErr wbc_create_logon_info(struct winbindd_response *resp, struct wbcLogonUserInfo **_i) { wbcErr wbc_status = WBC_ERR_SUCCESS; struct wbcLogonUserInfo *i; - i = talloc_zero(mem_ctx, struct wbcLogonUserInfo); + i = (struct wbcLogonUserInfo *)wbcAllocateMemory( + 1, sizeof(struct wbcLogonUserInfo), + wbcLogonUserInfoDestructor); BAIL_ON_PTR_ERROR(i, wbc_status); - wbc_status = wbc_create_auth_info(i, resp, &i->info); + wbc_status = wbc_create_auth_info(resp, &i->info); BAIL_ON_WBC_ERROR(wbc_status); - if (resp->data.auth.krb5ccname && - strlen(resp->data.auth.krb5ccname)) { + if (resp->data.auth.krb5ccname[0] != '\0') { wbc_status = wbcAddNamedBlob(&i->num_blobs, &i->blobs, "krb5ccname", @@ -280,8 +323,7 @@ static wbcErr wbc_create_logon_info(TALLOC_CTX *mem_ctx, BAIL_ON_WBC_ERROR(wbc_status); } - if (resp->data.auth.unix_username && - strlen(resp->data.auth.unix_username)) { + if (resp->data.auth.unix_username[0] != '\0') { wbc_status = wbcAddNamedBlob(&i->num_blobs, &i->blobs, "unix_username", @@ -294,14 +336,11 @@ static wbcErr wbc_create_logon_info(TALLOC_CTX *mem_ctx, *_i = i; i = NULL; done: - if (!WBC_ERROR_IS_OK(wbc_status) && i) { - wbcFreeMemory(i->blobs); - } - - talloc_free(i); + wbcFreeMemory(i); return wbc_status; } + /* Authenticate with more detailed information */ wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params, struct wbcAuthUserInfo **info, @@ -436,7 +475,8 @@ wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params, if (params->password.response.nt_length > sizeof(request.data.auth_crap.nt_resp)) { request.flags |= WBFLAG_BIG_NTLMV2_BLOB; request.extra_len = params->password.response.nt_length; - request.extra_data.data = talloc_zero_array(NULL, char, request.extra_len); + request.extra_data.data = (char *)malloc( + request.extra_len); if (request.extra_data.data == NULL) { wbc_status = WBC_ERR_NO_MEMORY; BAIL_ON_WBC_ERROR(wbc_status); @@ -470,8 +510,7 @@ wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params, } if (response.data.auth.nt_status != 0) { if (error) { - wbc_status = wbc_create_error_info(NULL, - &response, + wbc_status = wbc_create_error_info(&response, error); BAIL_ON_WBC_ERROR(wbc_status); } @@ -482,17 +521,14 @@ wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params, BAIL_ON_WBC_ERROR(wbc_status); if (info) { - wbc_status = wbc_create_auth_info(NULL, - &response, - info); + wbc_status = wbc_create_auth_info(&response, info); BAIL_ON_WBC_ERROR(wbc_status); } done: - if (response.extra_data.data) - free(response.extra_data.data); + winbindd_free_response(&response); - talloc_free(request.extra_data.data); + free(request.extra_data.data); return wbc_status; } @@ -519,8 +555,7 @@ wbcErr wbcCheckTrustCredentials(const char *domain, &request, &response); if (response.data.auth.nt_status != 0) { if (error) { - wbc_status = wbc_create_error_info(NULL, - &response, + wbc_status = wbc_create_error_info(&response, error); BAIL_ON_WBC_ERROR(wbc_status); } @@ -556,8 +591,7 @@ wbcErr wbcChangeTrustCredentials(const char *domain, &request, &response); if (response.data.auth.nt_status != 0) { if (error) { - wbc_status = wbc_create_error_info(NULL, - &response, + wbc_status = wbc_create_error_info(&response, error); BAIL_ON_WBC_ERROR(wbc_status); } @@ -600,8 +634,7 @@ wbcErr wbcPingDc(const char *domain, struct wbcAuthErrorInfo **error) &response); if (response.data.auth.nt_status != 0) { if (error) { - wbc_status = wbc_create_error_info(NULL, - &response, + wbc_status = wbc_create_error_info(&response, error); BAIL_ON_WBC_ERROR(wbc_status); } @@ -687,8 +720,7 @@ wbcErr wbcLogoffUserEx(const struct wbcLogoffUserParams *params, /* Take the response above and return it to the caller */ if (response.data.auth.nt_status != 0) { if (error) { - wbc_status = wbc_create_error_info(NULL, - &response, + wbc_status = wbc_create_error_info(&response, error); BAIL_ON_WBC_ERROR(wbc_status); } @@ -757,7 +789,7 @@ wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params, if (!params->account_name) { wbc_status = WBC_ERR_INVALID_PARAM; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } if (error) { @@ -781,7 +813,7 @@ wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params, if (!params->account_name) { wbc_status = WBC_ERR_INVALID_PARAM; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } strncpy(request.data.chauthtok.user, params->account_name, @@ -805,55 +837,55 @@ wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params, if (!params->account_name || !params->domain_name) { wbc_status = WBC_ERR_INVALID_PARAM; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } if (params->old_password.response.old_lm_hash_enc_length && !params->old_password.response.old_lm_hash_enc_data) { wbc_status = WBC_ERR_INVALID_PARAM; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } if (params->old_password.response.old_lm_hash_enc_length == 0 && params->old_password.response.old_lm_hash_enc_data) { wbc_status = WBC_ERR_INVALID_PARAM; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } if (params->old_password.response.old_nt_hash_enc_length && !params->old_password.response.old_nt_hash_enc_data) { wbc_status = WBC_ERR_INVALID_PARAM; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } if (params->old_password.response.old_nt_hash_enc_length == 0 && params->old_password.response.old_nt_hash_enc_data) { wbc_status = WBC_ERR_INVALID_PARAM; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } if (params->new_password.response.lm_length && !params->new_password.response.lm_data) { wbc_status = WBC_ERR_INVALID_PARAM; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } if (params->new_password.response.lm_length == 0 && params->new_password.response.lm_data) { wbc_status = WBC_ERR_INVALID_PARAM; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } if (params->new_password.response.nt_length && !params->new_password.response.nt_data) { wbc_status = WBC_ERR_INVALID_PARAM; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } if (params->new_password.response.nt_length == 0 && params->new_password.response.nt_data) { wbc_status = WBC_ERR_INVALID_PARAM; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } strncpy(request.data.chng_pswd_auth_crap.user, @@ -899,7 +931,7 @@ wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params, break; default: wbc_status = WBC_ERR_INVALID_PARAM; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; break; } @@ -916,8 +948,7 @@ wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params, if (response.data.auth.nt_status != 0) { if (error) { - wbc_status = wbc_create_error_info(NULL, - &response, + wbc_status = wbc_create_error_info(&response, error); BAIL_ON_WBC_ERROR(wbc_status); } @@ -925,8 +956,7 @@ wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params, } if (policy) { - wbc_status = wbc_create_password_policy_info(NULL, - &response, + wbc_status = wbc_create_password_policy_info(&response, policy); BAIL_ON_WBC_ERROR(wbc_status); } @@ -974,7 +1004,6 @@ wbcErr wbcLogonUser(const struct wbcLogonUserParams *params, struct wbcUserPasswordPolicyInfo **policy) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; - int cmd = 0; struct winbindd_request request; struct winbindd_response response; uint32_t i; @@ -1013,7 +1042,6 @@ wbcErr wbcLogonUser(const struct wbcLogonUserParams *params, /* Initialize request */ - cmd = WINBINDD_PAM_AUTH; request.flags = WBFLAG_PAM_INFO3_TEXT | WBFLAG_PAM_USER_SESSION_KEY | WBFLAG_PAM_LMKEY; @@ -1075,14 +1103,13 @@ wbcErr wbcLogonUser(const struct wbcLogonUserParams *params, } } - wbc_status = wbcRequestResponse(cmd, + wbc_status = wbcRequestResponse(WINBINDD_PAM_AUTH, &request, &response); if (response.data.auth.nt_status != 0) { if (error) { - wbc_status = wbc_create_error_info(NULL, - &response, + wbc_status = wbc_create_error_info(&response, error); BAIL_ON_WBC_ERROR(wbc_status); } @@ -1093,26 +1120,30 @@ wbcErr wbcLogonUser(const struct wbcLogonUserParams *params, BAIL_ON_WBC_ERROR(wbc_status); if (info) { - wbc_status = wbc_create_logon_info(NULL, - &response, + wbc_status = wbc_create_logon_info(&response, info); BAIL_ON_WBC_ERROR(wbc_status); } if (policy) { - wbc_status = wbc_create_password_policy_info(NULL, - &response, + wbc_status = wbc_create_password_policy_info(&response, policy); BAIL_ON_WBC_ERROR(wbc_status); } done: - if (response.extra_data.data) - free(response.extra_data.data); + winbindd_free_response(&response); return wbc_status; } +static void wbcCredentialCacheInfoDestructor(void *ptr) +{ + struct wbcCredentialCacheInfo *i = + (struct wbcCredentialCacheInfo *)ptr; + wbcFreeMemory(i->blobs); +} + /* Authenticate a user with cached credentials */ wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params, struct wbcCredentialCacheInfo **info, @@ -1186,8 +1217,7 @@ wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params, } if (request.extra_len != 0) { - request.extra_data.data = talloc_array( - NULL, char, request.extra_len); + request.extra_data.data = (char *)malloc(request.extra_len); if (request.extra_data.data == NULL) { status = WBC_ERR_NO_MEMORY; goto fail; @@ -1210,17 +1240,15 @@ wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params, goto fail; } - result = talloc(NULL, struct wbcCredentialCacheInfo); + result = (struct wbcCredentialCacheInfo *)wbcAllocateMemory( + 1, sizeof(struct wbcCredentialCacheInfo), + wbcCredentialCacheInfoDestructor); if (result == NULL) { status = WBC_ERR_NO_MEMORY; goto fail; } result->num_blobs = 0; - result->blobs = talloc(result, struct wbcNamedBlob); - if (result->blobs == NULL) { - status = WBC_ERR_NO_MEMORY; - goto fail; - } + result->blobs = NULL; status = wbcAddNamedBlob(&result->num_blobs, &result->blobs, "auth_blob", 0, (uint8_t *)response.extra_data.data, @@ -1236,16 +1264,13 @@ wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params, goto fail; } - if (response.extra_data.data) - free(response.extra_data.data); *info = result; - return WBC_ERR_SUCCESS; - + result = NULL; + status = WBC_ERR_SUCCESS; fail: - TALLOC_FREE(request.extra_data.data); - if (response.extra_data.data) - free(response.extra_data.data); - talloc_free(result); + free(request.extra_data.data); + winbindd_free_response(&response); + wbcFreeMemory(result); return status; } diff --git a/nsswitch/libwbclient/wbc_pwd.c b/nsswitch/libwbclient/wbc_pwd.c index 897bf1f5c3..6df694dcac 100644 --- a/nsswitch/libwbclient/wbc_pwd.c +++ b/nsswitch/libwbclient/wbc_pwd.c @@ -24,6 +24,7 @@ #include "replace.h" #include "libwbclient.h" +#include "../winbind_client.h" /** @brief The maximum number of pwent structs to get from winbindd * @@ -39,74 +40,116 @@ * **/ -static struct passwd *copy_passwd_entry(struct winbindd_pw *p) +static void wbcPasswdDestructor(void *ptr) { - struct passwd *pwd = NULL; - wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; - - pwd = talloc(NULL, struct passwd); - BAIL_ON_PTR_ERROR(pwd, wbc_status); + struct passwd *pw = (struct passwd *)ptr; + free(pw->pw_name); + free(pw->pw_passwd); + free(pw->pw_gecos); + free(pw->pw_shell); + free(pw->pw_dir); +} - pwd->pw_name = talloc_strdup(pwd,p->pw_name); - BAIL_ON_PTR_ERROR(pwd->pw_name, wbc_status); +static struct passwd *copy_passwd_entry(struct winbindd_pw *p) +{ + struct passwd *pw = NULL; - pwd->pw_passwd = talloc_strdup(pwd, p->pw_passwd); - BAIL_ON_PTR_ERROR(pwd->pw_passwd, wbc_status); + pw = (struct passwd *)wbcAllocateMemory(1, sizeof(struct passwd), + wbcPasswdDestructor); + if (pw == NULL) { + return NULL; + } + pw->pw_name = strdup(p->pw_name); + if (pw->pw_name == NULL) { + goto fail; + } + pw->pw_passwd = strdup(p->pw_passwd); + if (pw->pw_passwd == NULL) { + goto fail; + } + pw->pw_gecos = strdup(p->pw_gecos); + if (pw->pw_gecos == NULL) { + goto fail; + } + pw->pw_shell = strdup(p->pw_shell); + if (pw->pw_shell == NULL) { + goto fail; + } + pw->pw_dir = strdup(p->pw_dir); + if (pw->pw_dir == NULL) { + goto fail; + } + pw->pw_uid = p->pw_uid; + pw->pw_gid = p->pw_gid; + return pw; - pwd->pw_gecos = talloc_strdup(pwd, p->pw_gecos); - BAIL_ON_PTR_ERROR(pwd->pw_gecos, wbc_status); +fail: + wbcFreeMemory(pw); + return NULL; +} - pwd->pw_shell = talloc_strdup(pwd, p->pw_shell); - BAIL_ON_PTR_ERROR(pwd->pw_shell, wbc_status); +/** + * + **/ - pwd->pw_dir = talloc_strdup(pwd, p->pw_dir); - BAIL_ON_PTR_ERROR(pwd->pw_dir, wbc_status); +static void wbcGroupDestructor(void *ptr) +{ + struct group *gr = (struct group *)ptr; + int i; - pwd->pw_uid = p->pw_uid; - pwd->pw_gid = p->pw_gid; + free(gr->gr_name); + free(gr->gr_passwd); -done: - if (!WBC_ERROR_IS_OK(wbc_status)) { - talloc_free(pwd); - pwd = NULL; + /* if the array was partly created this can be NULL */ + if (gr->gr_mem == NULL) { + return; } - return pwd; + for (i=0; gr->gr_mem[i] != NULL; i++) { + free(gr->gr_mem[i]); + } + free(gr->gr_mem); } -/** - * - **/ - static struct group *copy_group_entry(struct winbindd_gr *g, char *mem_buf) { - struct group *grp = NULL; - wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + struct group *gr = NULL; int i; char *mem_p, *mem_q; - grp = talloc(NULL, struct group); - BAIL_ON_PTR_ERROR(grp, wbc_status); - - grp->gr_name = talloc_strdup(grp, g->gr_name); - BAIL_ON_PTR_ERROR(grp->gr_name, wbc_status); - - grp->gr_passwd = talloc_strdup(grp, g->gr_passwd); - BAIL_ON_PTR_ERROR(grp->gr_passwd, wbc_status); + gr = (struct group *)wbcAllocateMemory( + 1, sizeof(struct group), wbcGroupDestructor); + if (gr == NULL) { + return NULL; + } - grp->gr_gid = g->gr_gid; + gr->gr_name = strdup(g->gr_name); + if (gr->gr_name == NULL) { + goto fail; + } + gr->gr_passwd = strdup(g->gr_passwd); + if (gr->gr_passwd == NULL) { + goto fail; + } + gr->gr_gid = g->gr_gid; - grp->gr_mem = talloc_array(grp, char*, g->num_gr_mem+1); + gr->gr_mem = (char **)calloc(g->num_gr_mem+1, sizeof(char *)); + if (gr->gr_mem == NULL) { + goto fail; + } mem_p = mem_q = mem_buf; for (i=0; i<g->num_gr_mem && mem_p; i++) { - if ((mem_q = strchr(mem_p, ',')) != NULL) { + mem_q = strchr(mem_p, ','); + if (mem_q != NULL) { *mem_q = '\0'; } - grp->gr_mem[i] = talloc_strdup(grp, mem_p); - BAIL_ON_PTR_ERROR(grp->gr_mem[i], wbc_status); + gr->gr_mem[i] = strdup(mem_p); + if (gr->gr_mem[i] == NULL) { + goto fail; + } if (mem_q == NULL) { i += 1; @@ -114,17 +157,13 @@ static struct group *copy_group_entry(struct winbindd_gr *g, } mem_p = mem_q + 1; } - grp->gr_mem[i] = NULL; + gr->gr_mem[i] = NULL; - wbc_status = WBC_ERR_SUCCESS; + return gr; -done: - if (!WBC_ERROR_IS_OK(wbc_status)) { - talloc_free(grp); - grp = NULL; - } - - return grp; +fail: + wbcFreeMemory(gr); + return NULL; } /* Fill in a struct passwd* for a domain user based on username */ @@ -197,22 +236,18 @@ wbcErr wbcGetpwsid(struct wbcDomainSid *sid, struct passwd **pwd) wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct winbindd_request request; struct winbindd_response response; - char * sid_string = NULL; if (!pwd) { wbc_status = WBC_ERR_INVALID_PARAM; BAIL_ON_WBC_ERROR(wbc_status); } - wbc_status = wbcSidToString(sid, &sid_string); - BAIL_ON_WBC_ERROR(wbc_status); - /* Initialize request */ ZERO_STRUCT(request); ZERO_STRUCT(response); - strncpy(request.data.sid, sid_string, sizeof(request.data.sid)); + wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid)); wbc_status = wbcRequestResponse(WINBINDD_GETPWSID, &request, @@ -223,10 +258,6 @@ wbcErr wbcGetpwsid(struct wbcDomainSid *sid, struct passwd **pwd) BAIL_ON_PTR_ERROR(*pwd, wbc_status); done: - if (sid_string) { - wbcFreeMemory(sid_string); - } - return wbc_status; } @@ -261,8 +292,7 @@ wbcErr wbcGetgrnam(const char *name, struct group **grp) BAIL_ON_PTR_ERROR(*grp, wbc_status); done: - if (response.extra_data.data) - free(response.extra_data.data); + winbindd_free_response(&response); return wbc_status; } @@ -296,8 +326,7 @@ wbcErr wbcGetgrgid(gid_t gid, struct group **grp) BAIL_ON_PTR_ERROR(*grp, wbc_status); done: - if (response.extra_data.data) - free(response.extra_data.data); + winbindd_free_response(&response); return wbc_status; } @@ -324,9 +353,7 @@ wbcErr wbcSetpwent(void) if (pw_cache_size > 0) { pw_cache_idx = pw_cache_size = 0; - if (pw_response.extra_data.data) { - free(pw_response.extra_data.data); - } + winbindd_free_response(&pw_response); } ZERO_STRUCT(pw_response); @@ -346,9 +373,7 @@ wbcErr wbcEndpwent(void) if (pw_cache_size > 0) { pw_cache_idx = pw_cache_size = 0; - if (pw_response.extra_data.data) { - free(pw_response.extra_data.data); - } + winbindd_free_response(&pw_response); } wbc_status = wbcRequestResponse(WINBINDD_ENDPWENT, @@ -375,10 +400,7 @@ wbcErr wbcGetpwent(struct passwd **pwd) pw_cache_idx = 0; - if (pw_response.extra_data.data) { - free(pw_response.extra_data.data); - ZERO_STRUCT(pw_response); - } + winbindd_free_response(&pw_response); ZERO_STRUCT(request); request.data.num_entries = MAX_GETPWENT_USERS; @@ -426,9 +448,7 @@ wbcErr wbcSetgrent(void) if (gr_cache_size > 0) { gr_cache_idx = gr_cache_size = 0; - if (gr_response.extra_data.data) { - free(gr_response.extra_data.data); - } + winbindd_free_response(&gr_response); } ZERO_STRUCT(gr_response); @@ -448,9 +468,7 @@ wbcErr wbcEndgrent(void) if (gr_cache_size > 0) { gr_cache_idx = gr_cache_size = 0; - if (gr_response.extra_data.data) { - free(gr_response.extra_data.data); - } + winbindd_free_response(&gr_response); } wbc_status = wbcRequestResponse(WINBINDD_ENDGRENT, @@ -478,10 +496,7 @@ wbcErr wbcGetgrent(struct group **grp) gr_cache_idx = 0; - if (gr_response.extra_data.data) { - free(gr_response.extra_data.data); - ZERO_STRUCT(gr_response); - } + winbindd_free_response(&gr_response); ZERO_STRUCT(request); request.data.num_entries = MAX_GETGRENT_GROUPS; @@ -527,10 +542,8 @@ wbcErr wbcGetgrlist(struct group **grp) gr_cache_idx = 0; - if (gr_response.extra_data.data) { - free(gr_response.extra_data.data); - ZERO_STRUCT(gr_response); - } + winbindd_free_response(&gr_response); + ZERO_STRUCT(gr_response); ZERO_STRUCT(request); request.data.num_entries = MAX_GETGRENT_GROUPS; @@ -586,7 +599,8 @@ wbcErr wbcGetGroups(const char *account, &response); BAIL_ON_WBC_ERROR(wbc_status); - groups = talloc_array(NULL, gid_t, response.data.num_entries); + groups = (gid_t *)wbcAllocateMemory( + response.data.num_entries, sizeof(gid_t), NULL); BAIL_ON_PTR_ERROR(groups, wbc_status); for (i = 0; i < response.data.num_entries; i++) { @@ -600,12 +614,7 @@ wbcErr wbcGetGroups(const char *account, wbc_status = WBC_ERR_SUCCESS; done: - if (response.extra_data.data) { - free(response.extra_data.data); - } - if (groups) { - talloc_free(groups); - } - + winbindd_free_response(&response); + wbcFreeMemory(groups); return wbc_status; } diff --git a/nsswitch/libwbclient/wbc_sid.c b/nsswitch/libwbclient/wbc_sid.c index 99c9d8e152..6df8a3c375 100644 --- a/nsswitch/libwbclient/wbc_sid.c +++ b/nsswitch/libwbclient/wbc_sid.c @@ -4,6 +4,7 @@ Winbind client API Copyright (C) Gerald (Jerry) Carter 2007 + Copyright (C) Volker Lendecke 2010 This library is free software; you can redistribute it and/or @@ -24,47 +25,67 @@ #include "replace.h" #include "libwbclient.h" +#include "../winbind_client.h" - -/* Convert a binary SID to a character string */ -wbcErr wbcSidToString(const struct wbcDomainSid *sid, - char **sid_string) +/* Convert a sid to a string into a buffer. Return the string + * length. If buflen is too small, return the string length that would + * result if it was long enough. */ +int wbcSidToStringBuf(const struct wbcDomainSid *sid, char *buf, int buflen) { - wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; uint32_t id_auth; - int i; - char *tmp = NULL; + int i, ofs; if (!sid) { - wbc_status = WBC_ERR_INVALID_SID; - BAIL_ON_WBC_ERROR(wbc_status); + strlcpy(buf, "(NULL SID)", buflen); + return 10; /* strlen("(NULL SID)") */ } + /* + * BIG NOTE: this function only does SIDS where the identauth is not + * >= ^32 in a range of 2^48. + */ + id_auth = sid->id_auth[5] + (sid->id_auth[4] << 8) + (sid->id_auth[3] << 16) + (sid->id_auth[2] << 24); - tmp = talloc_asprintf(NULL, "S-%d-%d", sid->sid_rev_num, id_auth); - BAIL_ON_PTR_ERROR(tmp, wbc_status); + ofs = snprintf(buf, buflen, "S-%u-%lu", + (unsigned int)sid->sid_rev_num, (unsigned long)id_auth); - for (i=0; i<sid->num_auths; i++) { - char *tmp2; - tmp2 = talloc_asprintf_append(tmp, "-%u", sid->sub_auths[i]); - BAIL_ON_PTR_ERROR(tmp2, wbc_status); + for (i = 0; i < sid->num_auths; i++) { + ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "-%lu", + (unsigned long)sid->sub_auths[i]); + } + return ofs; +} - tmp = tmp2; +/* Convert a binary SID to a character string */ +wbcErr wbcSidToString(const struct wbcDomainSid *sid, + char **sid_string) +{ + char buf[WBC_SID_STRING_BUFLEN]; + char *result; + int len; + + if (!sid) { + return WBC_ERR_INVALID_SID; } - *sid_string = tmp; - tmp = NULL; + len = wbcSidToStringBuf(sid, buf, sizeof(buf)); - wbc_status = WBC_ERR_SUCCESS; + if (len+1 > sizeof(buf)) { + return WBC_ERR_INVALID_SID; + } -done: - talloc_free(tmp); + result = (char *)wbcAllocateMemory(len+1, 1, NULL); + if (result == NULL) { + return WBC_ERR_NO_MEMORY; + } + memcpy(result, buf, len+1); - return wbc_status; + *sid_string = result; + return WBC_ERR_SUCCESS; } /* Convert a character string to a binary SID */ @@ -131,8 +152,9 @@ wbcErr wbcStringToSid(const char *str, } sid->sub_auths[sid->num_auths++] = x; - if ((*q!='-') || (*q=='\0')) + if (*q != '-') { break; + } p = q + 1; } @@ -150,6 +172,7 @@ done: } + /* Convert a domain and name to SID */ wbcErr wbcLookupName(const char *domain, const char *name, @@ -193,6 +216,7 @@ wbcErr wbcLookupName(const char *domain, return wbc_status; } + /* Convert a SID to a domain and name */ wbcErr wbcLookupSid(const struct wbcDomainSid *sid, char **pdomain, @@ -202,14 +226,10 @@ wbcErr wbcLookupSid(const struct wbcDomainSid *sid, struct winbindd_request request; struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; - char *sid_string = NULL; - char *domain = NULL; - char *name = NULL; - enum wbcSidType name_type = WBC_SID_NAME_USE_NONE; + char *domain, *name; if (!sid) { - wbc_status = WBC_ERR_INVALID_PARAM; - BAIL_ON_WBC_ERROR(wbc_status); + return WBC_ERR_INVALID_PARAM; } /* Initialize request */ @@ -217,67 +237,228 @@ wbcErr wbcLookupSid(const struct wbcDomainSid *sid, ZERO_STRUCT(request); ZERO_STRUCT(response); - /* dst is already null terminated from the memset above */ - - wbc_status = wbcSidToString(sid, &sid_string); - BAIL_ON_WBC_ERROR(wbc_status); - - strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1); - wbcFreeMemory(sid_string); + wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid)); /* Make request */ - wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSID, - &request, - &response); - BAIL_ON_WBC_ERROR(wbc_status); + wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSID, &request, + &response); + if (!WBC_ERROR_IS_OK(wbc_status)) { + return wbc_status; + } /* Copy out result */ - domain = talloc_strdup(NULL, response.data.name.dom_name); - BAIL_ON_PTR_ERROR(domain, wbc_status); + wbc_status = WBC_ERR_NO_MEMORY; + domain = NULL; + name = NULL; - name = talloc_strdup(NULL, response.data.name.name); - BAIL_ON_PTR_ERROR(name, wbc_status); + domain = wbcStrDup(response.data.name.dom_name); + if (domain == NULL) { + goto done; + } + name = wbcStrDup(response.data.name.name); + if (name == NULL) { + goto done; + } + if (pdomain != NULL) { + *pdomain = domain; + domain = NULL; + } + if (pname != NULL) { + *pname = name; + name = NULL; + } + if (pname_type != NULL) { + *pname_type = (enum wbcSidType)response.data.name.type; + } + wbc_status = WBC_ERR_SUCCESS; +done: + wbcFreeMemory(name); + wbcFreeMemory(domain); + return wbc_status; +} - name_type = (enum wbcSidType)response.data.name.type; +static void wbcDomainInfosDestructor(void *ptr) +{ + struct wbcDomainInfo *i = (struct wbcDomainInfo *)ptr; - wbc_status = WBC_ERR_SUCCESS; + while (i->short_name != NULL) { + wbcFreeMemory(i->short_name); + wbcFreeMemory(i->dns_name); + i += 1; + } +} - done: - if (WBC_ERROR_IS_OK(wbc_status)) { - if (pdomain != NULL) { - *pdomain = domain; - } else { - TALLOC_FREE(domain); +static void wbcTranslatedNamesDestructor(void *ptr) +{ + struct wbcTranslatedName *n = (struct wbcTranslatedName *)ptr; + + while (n->name != NULL) { + free(n->name); + n += 1; + } +} + +wbcErr wbcLookupSids(const struct wbcDomainSid *sids, int num_sids, + struct wbcDomainInfo **pdomains, int *pnum_domains, + struct wbcTranslatedName **pnames) +{ + struct winbindd_request request; + struct winbindd_response response; + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + int buflen, i, extra_len, num_domains, num_names; + char *sidlist, *p, *q, *extra_data; + struct wbcDomainInfo *domains = NULL; + struct wbcTranslatedName *names = NULL; + + buflen = num_sids * (WBC_SID_STRING_BUFLEN + 1) + 1; + + sidlist = (char *)malloc(buflen); + if (sidlist == NULL) { + return WBC_ERR_NO_MEMORY; + } + + p = sidlist; + + for (i=0; i<num_sids; i++) { + int remaining; + int len; + + remaining = buflen - (p - sidlist); + + len = wbcSidToStringBuf(&sids[i], p, remaining); + if (len > remaining) { + free(sidlist); + return WBC_ERR_UNKNOWN_FAILURE; } - if (pname != NULL) { - *pname = name; - } else { - TALLOC_FREE(name); + + p += len; + *p++ = '\n'; + } + *p++ = '\0'; + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + request.extra_data.data = sidlist; + request.extra_len = p - sidlist; + + wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSIDS, + &request, &response); + free(sidlist); + if (!WBC_ERROR_IS_OK(wbc_status)) { + return wbc_status; + } + + extra_len = response.length - sizeof(struct winbindd_response); + extra_data = (char *)response.extra_data.data; + + if ((extra_len <= 0) || (extra_data[extra_len-1] != '\0')) { + goto wbc_err_invalid; + } + + p = extra_data; + + num_domains = strtoul(p, &q, 10); + if (*q != '\n') { + goto wbc_err_invalid; + } + p = q+1; + + domains = (struct wbcDomainInfo *)wbcAllocateMemory( + num_domains+1, sizeof(struct wbcDomainInfo), + wbcDomainInfosDestructor); + if (domains == NULL) { + wbc_status = WBC_ERR_NO_MEMORY; + goto fail; + } + + for (i=0; i<num_domains; i++) { + + q = strchr(p, ' '); + if (q == NULL) { + goto wbc_err_invalid; } - if (pname_type != NULL) { - *pname_type = name_type; + *q = '\0'; + wbc_status = wbcStringToSid(p, &domains[i].sid); + if (!WBC_ERROR_IS_OK(wbc_status)) { + goto fail; } + p = q+1; + + q = strchr(p, '\n'); + if (q == NULL) { + goto wbc_err_invalid; + } + *q = '\0'; + domains[i].short_name = wbcStrDup(p); + if (domains[i].short_name == NULL) { + wbc_status = WBC_ERR_NO_MEMORY; + goto fail; + } + p = q+1; } - else { -#if 0 - /* - * Found by Coverity: In this particular routine we can't end - * up here with a non-NULL name. Further up there are just two - * exit paths that lead here, neither of which leave an - * allocated name. If you add more paths up there, re-activate - * this. - */ - if (name != NULL) { - talloc_free(name); + + num_names = strtoul(p, &q, 10); + if (*q != '\n') { + goto wbc_err_invalid; + } + p = q+1; + + if (num_names != num_sids) { + goto wbc_err_invalid; + } + + names = (struct wbcTranslatedName *)wbcAllocateMemory( + num_names+1, sizeof(struct wbcTranslatedName), + wbcTranslatedNamesDestructor); + if (names == NULL) { + wbc_status = WBC_ERR_NO_MEMORY; + goto fail; + } + + for (i=0; i<num_names; i++) { + + names[i].domain_index = strtoul(p, &q, 10); + if (*q != ' ') { + goto wbc_err_invalid; } -#endif - if (domain != NULL) { - talloc_free(domain); + p = q+1; + + names[i].type = strtoul(p, &q, 10); + if (*q != ' ') { + goto wbc_err_invalid; } + p = q+1; + + q = strchr(p, '\n'); + if (q == NULL) { + goto wbc_err_invalid; + } + *q = '\0'; + names[i].name = wbcStrDup(p); + if (names[i].name == NULL) { + wbc_status = WBC_ERR_NO_MEMORY; + goto fail; + } + p = q+1; } + if (*p != '\0') { + goto wbc_err_invalid; + } + + *pdomains = domains; + *pnames = names; + winbindd_free_response(&response); + return WBC_ERR_SUCCESS; +wbc_err_invalid: + wbc_status = WBC_ERR_INVALID_RESPONSE; +fail: + winbindd_free_response(&response); + wbcFreeMemory(domains); + wbcFreeMemory(names); return wbc_status; } @@ -295,7 +476,6 @@ wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid, char *p; struct winbindd_request request; struct winbindd_response response; - char *sid_string = NULL; char *domain_name = NULL; const char **names = NULL; enum wbcSidType *types = NULL; @@ -311,11 +491,7 @@ wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid, BAIL_ON_WBC_ERROR(wbc_status); } - wbc_status = wbcSidToString(dom_sid, &sid_string); - BAIL_ON_WBC_ERROR(wbc_status); - - strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1); - wbcFreeMemory(sid_string); + wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid)); /* Even if all the Rids were of maximum 32bit values, we would only have 11 bytes per rid in the final array @@ -324,36 +500,34 @@ wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid, ridbuf_size = (sizeof(char)*11) * num_rids + 1; - ridlist = talloc_zero_array(NULL, char, ridbuf_size); + ridlist = (char *)malloc(ridbuf_size); BAIL_ON_PTR_ERROR(ridlist, wbc_status); len = 0; - for (i=0; i<num_rids && (len-1)>0; i++) { - char ridstr[12]; - - len = strlen(ridlist); - p = ridlist + len; - - snprintf( ridstr, sizeof(ridstr)-1, "%u\n", rids[i]); - strncat(p, ridstr, ridbuf_size-len-1); + for (i=0; i<num_rids; i++) { + len += snprintf(ridlist + len, ridbuf_size - len, "%u\n", + rids[i]); } + ridlist[len] = '\0'; + len += 1; request.extra_data.data = ridlist; - request.extra_len = strlen(ridlist)+1; + request.extra_len = len; wbc_status = wbcRequestResponse(WINBINDD_LOOKUPRIDS, &request, &response); - talloc_free(ridlist); + free(ridlist); BAIL_ON_WBC_ERROR(wbc_status); - domain_name = talloc_strdup(NULL, response.data.domain_name); + domain_name = wbcStrDup(response.data.domain_name); BAIL_ON_PTR_ERROR(domain_name, wbc_status); - names = talloc_array(NULL, const char*, num_rids); + names = wbcAllocateStringArray(num_rids); BAIL_ON_PTR_ERROR(names, wbc_status); - types = talloc_array(NULL, enum wbcSidType, num_rids); + types = (enum wbcSidType *)wbcAllocateMemory( + num_rids, sizeof(enum wbcSidType), NULL); BAIL_ON_PTR_ERROR(types, wbc_status); p = (char *)response.extra_data.data; @@ -363,26 +537,26 @@ wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid, if (*p == '\0') { wbc_status = WBC_ERR_INVALID_RESPONSE; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } types[i] = (enum wbcSidType)strtoul(p, &q, 10); if (*q != ' ') { wbc_status = WBC_ERR_INVALID_RESPONSE; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } p = q+1; if ((q = strchr(p, '\n')) == NULL) { wbc_status = WBC_ERR_INVALID_RESPONSE; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } *q = '\0'; - names[i] = talloc_strdup(names, p); + names[i] = strdup(p); BAIL_ON_PTR_ERROR(names[i], wbc_status); p = q+1; @@ -390,15 +564,13 @@ wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid, if (*p != '\0') { wbc_status = WBC_ERR_INVALID_RESPONSE; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } wbc_status = WBC_ERR_SUCCESS; done: - if (response.extra_data.data) { - free(response.extra_data.data); - } + winbindd_free_response(&response); if (WBC_ERROR_IS_OK(wbc_status)) { *pp_domain_name = domain_name; @@ -406,12 +578,9 @@ wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid, *ptypes = types; } else { - if (domain_name) - talloc_free(domain_name); - if (names) - talloc_free(names); - if (types) - talloc_free(types); + wbcFreeMemory(domain_name); + wbcFreeMemory(names); + wbcFreeMemory(types); } return wbc_status; @@ -427,7 +596,6 @@ wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid, const char *s; struct winbindd_request request; struct winbindd_response response; - char *sid_string = NULL; struct wbcDomainSid *sids = NULL; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; int cmd; @@ -442,11 +610,7 @@ wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid, BAIL_ON_WBC_ERROR(wbc_status); } - wbc_status = wbcSidToString(user_sid, &sid_string); - BAIL_ON_WBC_ERROR(wbc_status); - - strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1); - wbcFreeMemory(sid_string); + wbcSidToStringBuf(user_sid, request.data.sid, sizeof(request.data.sid)); if (domain_groups_only) { cmd = WINBINDD_GETUSERDOMGROUPS; @@ -465,8 +629,9 @@ wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid, BAIL_ON_WBC_ERROR(wbc_status); } - sids = talloc_array(NULL, struct wbcDomainSid, - response.data.num_entries); + sids = (struct wbcDomainSid *)wbcAllocateMemory( + response.data.num_entries, sizeof(struct wbcDomainSid), + NULL); BAIL_ON_PTR_ERROR(sids, wbc_status); s = (const char *)response.extra_data.data; @@ -486,11 +651,9 @@ wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid, wbc_status = WBC_ERR_SUCCESS; done: - if (response.extra_data.data) { - free(response.extra_data.data); - } + winbindd_free_response(&response); if (sids) { - talloc_free(sids); + wbcFreeMemory(sids); } return wbc_status; @@ -518,8 +681,6 @@ wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid, const char *s; struct winbindd_request request; struct winbindd_response response; - char *sid_string = NULL; - ssize_t sid_len; ssize_t extra_data_len = 0; char * extra_data = NULL; ssize_t buflen = 0; @@ -534,52 +695,43 @@ wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid, if (!dom_sid) { wbc_status = WBC_ERR_INVALID_PARAM; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } - wbc_status = wbcSidToString(dom_sid, &sid_string); - BAIL_ON_WBC_ERROR(wbc_status); - - strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1); - wbcFreeMemory(sid_string); - sid_string = NULL; + wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid)); - /* Lets assume each sid is around 54 characters - * S-1-5-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */ - buflen = 54 * num_sids; - extra_data = talloc_array(NULL, char, buflen); + /* Lets assume each sid is around 57 characters + * S-1-5-21-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */ + buflen = 57 * num_sids; + extra_data = (char *)malloc(buflen); if (!extra_data) { wbc_status = WBC_ERR_NO_MEMORY; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } /* Build the sid list */ for (i=0; i<num_sids; i++) { - if (sid_string) { - wbcFreeMemory(sid_string); - sid_string = NULL; - } - wbc_status = wbcSidToString(&sids[i], &sid_string); - BAIL_ON_WBC_ERROR(wbc_status); + char sid_str[WBC_SID_STRING_BUFLEN]; + size_t sid_len; - sid_len = strlen(sid_string); + sid_len = wbcSidToStringBuf(&sids[i], sid_str, sizeof(sid_str)); if (buflen < extra_data_len + sid_len + 2) { buflen *= 2; - extra_data = talloc_realloc(NULL, extra_data, - char, buflen); + extra_data = (char *)realloc(extra_data, buflen); if (!extra_data) { wbc_status = WBC_ERR_NO_MEMORY; BAIL_ON_WBC_ERROR(wbc_status); } } - strncpy(&extra_data[extra_data_len], sid_string, + strncpy(&extra_data[extra_data_len], sid_str, buflen - extra_data_len); extra_data_len += sid_len; extra_data[extra_data_len++] = '\n'; extra_data[extra_data_len] = '\0'; } + extra_data_len += 1; request.extra_data.data = extra_data; request.extra_len = extra_data_len; @@ -592,11 +744,11 @@ wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid, if (response.data.num_entries && !response.extra_data.data) { wbc_status = WBC_ERR_INVALID_RESPONSE; - BAIL_ON_WBC_ERROR(wbc_status); + goto done; } - rids = talloc_array(NULL, uint32_t, - response.data.num_entries); + rids = (uint32_t *)wbcAllocateMemory(response.data.num_entries, + sizeof(uint32_t), NULL); BAIL_ON_PTR_ERROR(sids, wbc_status); s = (const char *)response.extra_data.data; @@ -618,19 +770,9 @@ wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid, wbc_status = WBC_ERR_SUCCESS; done: - if (sid_string) { - wbcFreeMemory(sid_string); - } - if (extra_data) { - talloc_free(extra_data); - } - if (response.extra_data.data) { - free(response.extra_data.data); - } - if (rids) { - talloc_free(rids); - } - + free(extra_data); + winbindd_free_response(&response); + wbcFreeMemory(rids); return wbc_status; } @@ -662,13 +804,26 @@ wbcErr wbcListUsers(const char *domain_name, &response); BAIL_ON_WBC_ERROR(wbc_status); + users = wbcAllocateStringArray(response.data.num_entries); + if (users == NULL) { + return WBC_ERR_NO_MEMORY; + } + /* Look through extra data */ next = (const char *)response.extra_data.data; while (next) { - const char **tmp; - const char *current = next; - char *k = strchr(next, ','); + const char *current; + char *k; + + if (num_users >= response.data.num_entries) { + wbc_status = WBC_ERR_INVALID_RESPONSE; + goto done; + } + + current = next; + k = strchr(next, ','); + if (k) { k[0] = '\0'; next = k+1; @@ -676,30 +831,23 @@ wbcErr wbcListUsers(const char *domain_name, next = NULL; } - tmp = talloc_realloc(NULL, users, - const char *, - num_users+1); - BAIL_ON_PTR_ERROR(tmp, wbc_status); - users = tmp; - - users[num_users] = talloc_strdup(users, current); + users[num_users] = strdup(current); BAIL_ON_PTR_ERROR(users[num_users], wbc_status); - - num_users++; + num_users += 1; + } + if (num_users != response.data.num_entries) { + wbc_status = WBC_ERR_INVALID_RESPONSE; + goto done; } - *_num_users = num_users; + *_num_users = response.data.num_entries; *_users = users; users = NULL; wbc_status = WBC_ERR_SUCCESS; done: - if (response.extra_data.data) { - free(response.extra_data.data); - } - if (users) { - talloc_free(users); - } + winbindd_free_response(&response); + wbcFreeMemory(users); return wbc_status; } @@ -730,13 +878,26 @@ wbcErr wbcListGroups(const char *domain_name, &response); BAIL_ON_WBC_ERROR(wbc_status); + groups = wbcAllocateStringArray(response.data.num_entries); + if (groups == NULL) { + return WBC_ERR_NO_MEMORY; + } + /* Look through extra data */ next = (const char *)response.extra_data.data; while (next) { - const char **tmp; - const char *current = next; - char *k = strchr(next, ','); + const char *current; + char *k; + + if (num_groups >= response.data.num_entries) { + wbc_status = WBC_ERR_INVALID_RESPONSE; + goto done; + } + + current = next; + k = strchr(next, ','); + if (k) { k[0] = '\0'; next = k+1; @@ -744,30 +905,23 @@ wbcErr wbcListGroups(const char *domain_name, next = NULL; } - tmp = talloc_realloc(NULL, groups, - const char *, - num_groups+1); - BAIL_ON_PTR_ERROR(tmp, wbc_status); - groups = tmp; - - groups[num_groups] = talloc_strdup(groups, current); + groups[num_groups] = strdup(current); BAIL_ON_PTR_ERROR(groups[num_groups], wbc_status); - - num_groups++; + num_groups += 1; + } + if (num_groups != response.data.num_entries) { + wbc_status = WBC_ERR_INVALID_RESPONSE; + goto done; } - *_num_groups = num_groups; + *_num_groups = response.data.num_entries; *_groups = groups; groups = NULL; wbc_status = WBC_ERR_SUCCESS; done: - if (response.extra_data.data) { - free(response.extra_data.data); - } - if (groups) { - talloc_free(groups); - } + winbindd_free_response(&response); + wbcFreeMemory(groups); return wbc_status; } @@ -796,7 +950,8 @@ wbcErr wbcGetDisplayName(const struct wbcDomainSid *sid, wbcFreeMemory(name); - name = talloc_strdup(NULL, pwd->pw_gecos); + name = wbcStrDup(pwd->pw_gecos); + wbcFreeMemory(pwd); BAIL_ON_PTR_ERROR(name, wbc_status); } diff --git a/nsswitch/libwbclient/wbc_util.c b/nsswitch/libwbclient/wbc_util.c index 16828ae5df..d783ba36d8 100644 --- a/nsswitch/libwbclient/wbc_util.c +++ b/nsswitch/libwbclient/wbc_util.c @@ -1,7 +1,7 @@ /* Unix SMB/CIFS implementation. - Winbind client API + Winbind client asynchronous API, utility functions Copyright (C) Gerald (Jerry) Carter 2007-2008 @@ -24,14 +24,12 @@ #include "replace.h" #include "libwbclient.h" - - +#include "../winbind_client.h" /** @brief Ping winbindd to see if the daemon is running * * @return #wbcErr **/ - wbcErr wbcPing(void) { struct winbindd_request request; @@ -45,6 +43,23 @@ wbcErr wbcPing(void) return wbcRequestResponse(WINBINDD_PING, &request, &response); } +static void wbcInterfaceDetailsDestructor(void *ptr) +{ + struct wbcInterfaceDetails *i = (struct wbcInterfaceDetails *)ptr; + free(i->winbind_version); + free(i->netbios_name); + free(i->netbios_domain); + free(i->dns_domain); +} + +/** + * @brief Query useful information about the winbind service + * + * @param *_details pointer to hold the struct wbcInterfaceDetails + * + * @return #wbcErr + */ + wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; @@ -58,7 +73,9 @@ wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details) ZERO_STRUCT(request); ZERO_STRUCT(response); - info = talloc(NULL, struct wbcInterfaceDetails); + info = (struct wbcInterfaceDetails *)wbcAllocateMemory( + 1, sizeof(struct wbcInterfaceDetails), + wbcInterfaceDetailsDestructor); BAIL_ON_PTR_ERROR(info, wbc_status); /* first the interface version */ @@ -70,8 +87,7 @@ wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details) wbc_status = wbcRequestResponse(WINBINDD_INFO, NULL, &response); BAIL_ON_WBC_ERROR(wbc_status); - info->winbind_version = talloc_strdup(info, - response.data.info.samba_version); + info->winbind_version = strdup(response.data.info.samba_version); BAIL_ON_PTR_ERROR(info->winbind_version, wbc_status); info->winbind_separator = response.data.info.winbind_separator; @@ -79,16 +95,14 @@ wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details) wbc_status = wbcRequestResponse(WINBINDD_NETBIOS_NAME, NULL, &response); BAIL_ON_WBC_ERROR(wbc_status); - info->netbios_name = talloc_strdup(info, - response.data.netbios_name); + info->netbios_name = strdup(response.data.netbios_name); BAIL_ON_PTR_ERROR(info->netbios_name, wbc_status); /* then the local workgroup name */ wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_NAME, NULL, &response); BAIL_ON_WBC_ERROR(wbc_status); - info->netbios_domain = talloc_strdup(info, - response.data.domain_name); + info->netbios_domain = strdup(response.data.domain_name); BAIL_ON_PTR_ERROR(info->netbios_domain, wbc_status); wbc_status = wbcDomainInfo(info->netbios_domain, &domain); @@ -101,8 +115,7 @@ wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details) } if (domain) { - info->dns_domain = talloc_strdup(info, - domain->dns_name); + info->dns_domain = strdup(domain->dns_name); wbcFreeMemory(domain); BAIL_ON_PTR_ERROR(info->dns_domain, wbc_status); } else { @@ -115,12 +128,25 @@ wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details) wbc_status = WBC_ERR_SUCCESS; done: - talloc_free(info); + wbcFreeMemory(info); return wbc_status; } +static void wbcDomainInfoDestructor(void *ptr) +{ + struct wbcDomainInfo *i = (struct wbcDomainInfo *)ptr; + free(i->short_name); + free(i->dns_name); +} + +/** @brief Lookup the current status of a trusted domain, sync wrapper + * + * @param domain Domain to query + * @param *dinfo Pointer to returned struct wbcDomainInfo + * + * @return #wbcErr + */ -/* Lookup the current status of a trusted domain */ wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo) { struct winbindd_request request; @@ -146,15 +172,14 @@ wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo) &response); BAIL_ON_WBC_ERROR(wbc_status); - info = talloc(NULL, struct wbcDomainInfo); + info = (struct wbcDomainInfo *)wbcAllocateMemory( + 1, sizeof(struct wbcDomainInfo), wbcDomainInfoDestructor); BAIL_ON_PTR_ERROR(info, wbc_status); - info->short_name = talloc_strdup(info, - response.data.domain_info.name); + info->short_name = strdup(response.data.domain_info.name); BAIL_ON_PTR_ERROR(info->short_name, wbc_status); - info->dns_name = talloc_strdup(info, - response.data.domain_info.alt_name); + info->dns_name = strdup(response.data.domain_info.alt_name); BAIL_ON_PTR_ERROR(info->dns_name, wbc_status); wbc_status = wbcStringToSid(response.data.domain_info.sid, @@ -169,18 +194,102 @@ wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo) info->domain_flags |= WBC_DOMINFO_DOMAIN_PRIMARY; *dinfo = info; + info = NULL; wbc_status = WBC_ERR_SUCCESS; done: - if (!WBC_ERROR_IS_OK(wbc_status)) { - talloc_free(info); + wbcFreeMemory(info); + return wbc_status; +} + +/* Get the list of current DCs */ +wbcErr wbcDcInfo(const char *domain, size_t *num_dcs, + const char ***dc_names, const char ***dc_ips) +{ + struct winbindd_request request; + struct winbindd_response response; + const char **names = NULL; + const char **ips = NULL; + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + size_t extra_len; + int i; + char *p; + + /* Initialise request */ + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + if (domain != NULL) { + strncpy(request.domain_name, domain, + sizeof(request.domain_name) - 1); } + wbc_status = wbcRequestResponse(WINBINDD_DC_INFO, + &request, &response); + BAIL_ON_WBC_ERROR(wbc_status); + + names = wbcAllocateStringArray(response.data.num_entries); + BAIL_ON_PTR_ERROR(names, wbc_status); + + ips = wbcAllocateStringArray(response.data.num_entries); + BAIL_ON_PTR_ERROR(ips, wbc_status); + + wbc_status = WBC_ERR_INVALID_RESPONSE; + + p = (char *)response.extra_data.data; + + if (response.length < (sizeof(struct winbindd_response)+1)) { + goto done; + } + + extra_len = response.length - sizeof(struct winbindd_response); + + if (p[extra_len-1] != '\0') { + goto done; + } + + for (i=0; i<response.data.num_entries; i++) { + char *q; + + q = strchr(p, '\n'); + if (q == NULL) { + goto done; + } + names[i] = strndup(p, q-p); + BAIL_ON_PTR_ERROR(names[i], wbc_status); + p = q+1; + + q = strchr(p, '\n'); + if (q == NULL) { + goto done; + } + ips[i] = strndup(p, q-p); + BAIL_ON_PTR_ERROR(ips[i], wbc_status); + p = q+1; + } + if (p[0] != '\0') { + goto done; + } + + wbc_status = WBC_ERR_SUCCESS; +done: + if (response.extra_data.data) + free(response.extra_data.data); + + if (WBC_ERROR_IS_OK(wbc_status)) { + *num_dcs = response.data.num_entries; + *dc_names = names; + names = NULL; + *dc_ips = ips; + ips = NULL; + } + wbcFreeMemory(names); + wbcFreeMemory(ips); return wbc_status; } - /* Resolve a NetbiosName via WINS */ wbcErr wbcResolveWinsByName(const char *name, char **ip) { @@ -204,7 +313,7 @@ wbcErr wbcResolveWinsByName(const char *name, char **ip) /* Display response */ - ipaddr = talloc_strdup(NULL, response.data.winsresp); + ipaddr = wbcStrDup(response.data.winsresp); BAIL_ON_PTR_ERROR(ipaddr, wbc_status); *ip = ipaddr; @@ -237,7 +346,7 @@ wbcErr wbcResolveWinsByIP(const char *ip, char **name) /* Display response */ - name_str = talloc_strdup(NULL, response.data.winsresp); + name_str = wbcStrDup(response.data.winsresp); BAIL_ON_PTR_ERROR(name_str, wbc_status); *name = name_str; @@ -250,21 +359,13 @@ wbcErr wbcResolveWinsByIP(const char *ip, char **name) /** */ -static wbcErr process_domain_info_string(TALLOC_CTX *ctx, - struct wbcDomainInfo *info, +static wbcErr process_domain_info_string(struct wbcDomainInfo *info, char *info_string) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; char *r = NULL; char *s = NULL; - if (!info || !info_string) { - wbc_status = WBC_ERR_INVALID_PARAM; - BAIL_ON_WBC_ERROR(wbc_status); - } - - ZERO_STRUCTP(info); - r = info_string; /* Short Name */ @@ -275,7 +376,7 @@ static wbcErr process_domain_info_string(TALLOC_CTX *ctx, *s = '\0'; s++; - info->short_name = talloc_strdup(ctx, r); + info->short_name = strdup(r); BAIL_ON_PTR_ERROR(info->short_name, wbc_status); @@ -288,7 +389,7 @@ static wbcErr process_domain_info_string(TALLOC_CTX *ctx, *s = '\0'; s++; - info->dns_name = talloc_strdup(ctx, r); + info->dns_name = strdup(r); BAIL_ON_PTR_ERROR(info->dns_name, wbc_status); /* SID */ @@ -381,15 +482,24 @@ static wbcErr process_domain_info_string(TALLOC_CTX *ctx, return wbc_status; } +static void wbcDomainInfoListDestructor(void *ptr) +{ + struct wbcDomainInfo *i = (struct wbcDomainInfo *)ptr; + + while (i->short_name != NULL) { + free(i->short_name); + free(i->dns_name); + i += 1; + } +} + /* Enumerate the domain trusts known by Winbind */ wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains) { struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; char *p = NULL; - char *q = NULL; char *extra_data = NULL; - int count = 0; struct wbcDomainInfo *d_list = NULL; int i = 0; @@ -417,18 +527,9 @@ wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains) BAIL_ON_WBC_ERROR(wbc_status); } - /* Count number of domains */ - - count = 0; - while (p) { - count++; - - if ((q = strchr(p, '\n')) != NULL) - q++; - p = q; - } - - d_list = talloc_array(NULL, struct wbcDomainInfo, count); + d_list = (struct wbcDomainInfo *)wbcAllocateMemory( + response.data.num_entries + 1,sizeof(struct wbcDomainInfo), + wbcDomainInfoListDestructor); BAIL_ON_PTR_ERROR(d_list, wbc_status); extra_data = strdup((char*)response.extra_data.data); @@ -438,7 +539,7 @@ wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains) /* Outer loop processes the list of domain information */ - for (i=0; i<count && p; i++) { + for (i=0; i<response.data.num_entries && p; i++) { char *next = strchr(p, '\n'); if (next) { @@ -446,26 +547,30 @@ wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains) next++; } - wbc_status = process_domain_info_string(d_list, &d_list[i], p); + wbc_status = process_domain_info_string(&d_list[i], p); BAIL_ON_WBC_ERROR(wbc_status); p = next; } *domains = d_list; + d_list = NULL; *num_domains = i; done: - if (!WBC_ERROR_IS_OK(wbc_status)) { - if (d_list) - talloc_free(d_list); - if (extra_data) - free(extra_data); - } - + winbindd_free_response(&response); + wbcFreeMemory(d_list); + free(extra_data); return wbc_status; } +static void wbcDomainControllerInfoDestructor(void *ptr) +{ + struct wbcDomainControllerInfo *i = + (struct wbcDomainControllerInfo *)ptr; + free(i->dc_name); +} + /* Enumerate the domain trusts known by Winbind */ wbcErr wbcLookupDomainController(const char *domain, uint32_t flags, @@ -491,7 +596,9 @@ wbcErr wbcLookupDomainController(const char *domain, request.flags = flags; - dc = talloc(NULL, struct wbcDomainControllerInfo); + dc = (struct wbcDomainControllerInfo *)wbcAllocateMemory( + 1, sizeof(struct wbcDomainControllerInfo), + wbcDomainControllerInfoDestructor); BAIL_ON_PTR_ERROR(dc, wbc_status); /* Send request */ @@ -501,82 +608,87 @@ wbcErr wbcLookupDomainController(const char *domain, &response); BAIL_ON_WBC_ERROR(wbc_status); - dc->dc_name = talloc_strdup(dc, response.data.dsgetdcname.dc_unc); + dc->dc_name = strdup(response.data.dsgetdcname.dc_unc); BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status); *dc_info = dc; + dc = NULL; done: - if (!WBC_ERROR_IS_OK(wbc_status)) { - talloc_free(dc); - } - + wbcFreeMemory(dc); return wbc_status; } -static wbcErr wbc_create_domain_controller_info_ex(TALLOC_CTX *mem_ctx, - const struct winbindd_response *resp, +static void wbcDomainControllerInfoExDestructor(void *ptr) +{ + struct wbcDomainControllerInfoEx *i = + (struct wbcDomainControllerInfoEx *)ptr; + free((char *)(i->dc_unc)); + free((char *)(i->dc_address)); + free((char *)(i->domain_guid)); + free((char *)(i->domain_name)); + free((char *)(i->forest_name)); + free((char *)(i->dc_site_name)); + free((char *)(i->client_site_name)); +} + +static wbcErr wbc_create_domain_controller_info_ex(const struct winbindd_response *resp, struct wbcDomainControllerInfoEx **_i) { wbcErr wbc_status = WBC_ERR_SUCCESS; struct wbcDomainControllerInfoEx *i; struct wbcGuid guid; - i = talloc(mem_ctx, struct wbcDomainControllerInfoEx); + i = (struct wbcDomainControllerInfoEx *)wbcAllocateMemory( + 1, sizeof(struct wbcDomainControllerInfoEx), + wbcDomainControllerInfoExDestructor); BAIL_ON_PTR_ERROR(i, wbc_status); - i->dc_unc = talloc_strdup(i, resp->data.dsgetdcname.dc_unc); + i->dc_unc = strdup(resp->data.dsgetdcname.dc_unc); BAIL_ON_PTR_ERROR(i->dc_unc, wbc_status); - i->dc_address = talloc_strdup(i, resp->data.dsgetdcname.dc_address); + i->dc_address = strdup(resp->data.dsgetdcname.dc_address); BAIL_ON_PTR_ERROR(i->dc_address, wbc_status); i->dc_address_type = resp->data.dsgetdcname.dc_address_type; wbc_status = wbcStringToGuid(resp->data.dsgetdcname.domain_guid, &guid); if (WBC_ERROR_IS_OK(wbc_status)) { - i->domain_guid = talloc(i, struct wbcGuid); + i->domain_guid = (struct wbcGuid *)malloc( + sizeof(struct wbcGuid)); BAIL_ON_PTR_ERROR(i->domain_guid, wbc_status); *i->domain_guid = guid; - } else { - i->domain_guid = NULL; } - i->domain_name = talloc_strdup(i, resp->data.dsgetdcname.domain_name); + i->domain_name = strdup(resp->data.dsgetdcname.domain_name); BAIL_ON_PTR_ERROR(i->domain_name, wbc_status); if (resp->data.dsgetdcname.forest_name[0] != '\0') { - i->forest_name = talloc_strdup(i, - resp->data.dsgetdcname.forest_name); + i->forest_name = strdup(resp->data.dsgetdcname.forest_name); BAIL_ON_PTR_ERROR(i->forest_name, wbc_status); - } else { - i->forest_name = NULL; } i->dc_flags = resp->data.dsgetdcname.dc_flags; if (resp->data.dsgetdcname.dc_site_name[0] != '\0') { - i->dc_site_name = talloc_strdup(i, - resp->data.dsgetdcname.dc_site_name); + i->dc_site_name = strdup(resp->data.dsgetdcname.dc_site_name); BAIL_ON_PTR_ERROR(i->dc_site_name, wbc_status); - } else { - i->dc_site_name = NULL; } if (resp->data.dsgetdcname.client_site_name[0] != '\0') { - i->client_site_name = talloc_strdup(i, + i->client_site_name = strdup( resp->data.dsgetdcname.client_site_name); BAIL_ON_PTR_ERROR(i->client_site_name, wbc_status); - } else { - i->client_site_name = NULL; } *_i = i; i = NULL; done: - talloc_free(i); + if (i != NULL) { + wbcFreeMemory(i); + } return wbc_status; } @@ -631,8 +743,7 @@ wbcErr wbcLookupDomainControllerEx(const char *domain, BAIL_ON_WBC_ERROR(wbc_status); if (dc_info) { - wbc_status = wbc_create_domain_controller_info_ex(NULL, - &response, + wbc_status = wbc_create_domain_controller_info_ex(&response, dc_info); BAIL_ON_WBC_ERROR(wbc_status); } @@ -642,35 +753,72 @@ done: return wbc_status; } +static void wbcNamedBlobDestructor(void *ptr) +{ + struct wbcNamedBlob *b = (struct wbcNamedBlob *)ptr; + + while (b->name != NULL) { + free((char *)(b->name)); + free(b->blob.data); + b += 1; + } +} + /* Initialize a named blob and add to list of blobs */ wbcErr wbcAddNamedBlob(size_t *num_blobs, - struct wbcNamedBlob **blobs, + struct wbcNamedBlob **pblobs, const char *name, uint32_t flags, uint8_t *data, size_t length) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; - struct wbcNamedBlob blob; + struct wbcNamedBlob *blobs, *blob; + + if (name == NULL) { + return WBC_ERR_INVALID_PARAM; + } + + /* + * Overallocate the b->name==NULL terminator for + * wbcNamedBlobDestructor + */ + blobs = (struct wbcNamedBlob *)wbcAllocateMemory( + *num_blobs + 2, sizeof(struct wbcNamedBlob), + wbcNamedBlobDestructor); + + if (blobs == NULL) { + return WBC_ERR_NO_MEMORY; + } + + if (*pblobs != NULL) { + struct wbcNamedBlob *old = *pblobs; + memcpy(blobs, old, sizeof(struct wbcNamedBlob) * (*num_blobs)); + if (*num_blobs != 0) { + /* end indicator for wbcNamedBlobDestructor */ + old[0].name = NULL; + } + wbcFreeMemory(old); + } + *pblobs = blobs; + + blob = &blobs[*num_blobs]; - *blobs = talloc_realloc(NULL, *blobs, struct wbcNamedBlob, - *(num_blobs)+1); - BAIL_ON_PTR_ERROR(*blobs, wbc_status); + blob->name = strdup(name); + BAIL_ON_PTR_ERROR(blob->name, wbc_status); + blob->flags = flags; - blob.name = talloc_strdup(*blobs, name); - BAIL_ON_PTR_ERROR(blob.name, wbc_status); - blob.flags = flags; - blob.blob.length = length; - blob.blob.data = (uint8_t *)talloc_memdup(*blobs, data, length); - BAIL_ON_PTR_ERROR(blob.blob.data, wbc_status); + blob->blob.length = length; + blob->blob.data = (uint8_t *)malloc(length); + BAIL_ON_PTR_ERROR(blob->blob.data, wbc_status); + memcpy(blob->blob.data, data, length); - (*(blobs))[*num_blobs] = blob; - *(num_blobs) += 1; + *num_blobs += 1; + *pblobs = blobs; + blobs = NULL; wbc_status = WBC_ERR_SUCCESS; done: - if (!WBC_ERROR_IS_OK(wbc_status) && blobs) { - wbcFreeMemory(*blobs); - } + wbcFreeMemory(blobs); return wbc_status; } diff --git a/nsswitch/libwbclient/wbclient.c b/nsswitch/libwbclient/wbclient.c index ec8d205647..19bb3e9e0a 100644 --- a/nsswitch/libwbclient/wbclient.c +++ b/nsswitch/libwbclient/wbclient.c @@ -23,8 +23,6 @@ /* Required Headers */ #include "replace.h" -#include "talloc.h" -#include "tevent.h" #include "libwbclient.h" /* From wb_common.c */ @@ -36,16 +34,7 @@ NSS_STATUS winbindd_priv_request_response(int req_type, struct winbindd_request *request, struct winbindd_response *response); -/** @brief Wrapper around Winbind's send/receive API call - * - * @param cmd Winbind command operation to perform - * @param request Send structure - * @param response Receive structure - * - * @return #wbcErr - **/ - -/********************************************************************** +/* result == NSS_STATUS_UNAVAIL: winbind not around result == NSS_STATUS_NOTFOUND: winbind around, but domain missing @@ -56,7 +45,7 @@ NSS_STATUS winbindd_priv_request_response(int req_type, (as far as I have seen) with the callers of is_trusted_domains. --Volker -**********************************************************************/ +*/ static wbcErr wbcRequestResponseInt( int cmd, @@ -91,6 +80,15 @@ static wbcErr wbcRequestResponseInt( return wbc_status; } +/** + * @brief Wrapper around Winbind's send/receive API call + * + * @param cmd Winbind command operation to perform + * @param request Send structure + * @param response Receive structure + * + * @return #wbcErr + */ wbcErr wbcRequestResponse(int cmd, struct winbindd_request *request, struct winbindd_response *response) @@ -149,35 +147,113 @@ const char *wbcErrorString(wbcErr error) return "unknown wbcErr value"; } +#define WBC_MAGIC (0x7a2b0e1e) +#define WBC_MAGIC_FREE (0x875634fe) + +struct wbcMemPrefix { + uint32_t magic; + void (*destructor)(void *ptr); +}; + +static size_t wbcPrefixLen(void) +{ + size_t result = sizeof(struct wbcMemPrefix); + return (result + 15) & ~15; +} + +static struct wbcMemPrefix *wbcMemToPrefix(void *ptr) +{ + return (struct wbcMemPrefix *)(((char *)ptr) - wbcPrefixLen()); +} + +void *wbcAllocateMemory(size_t nelem, size_t elsize, + void (*destructor)(void *ptr)) +{ + struct wbcMemPrefix *result; + + if (nelem >= (2<<24)/elsize) { + /* basic protection against integer wrap */ + return NULL; + } + + result = (struct wbcMemPrefix *)calloc( + 1, nelem*elsize + wbcPrefixLen()); + if (result == NULL) { + return NULL; + } + result->magic = WBC_MAGIC; + result->destructor = destructor; + return ((char *)result) + wbcPrefixLen(); +} + /* Free library allocated memory */ void wbcFreeMemory(void *p) { - if (p) - talloc_free(p); + struct wbcMemPrefix *wbcMem; + + if (p == NULL) { + return; + } + wbcMem = wbcMemToPrefix(p); + if (wbcMem->magic != WBC_MAGIC) { + return; + } + /* paranoid check to ensure we don't double free */ + wbcMem->magic = WBC_MAGIC_FREE; + + if (wbcMem->destructor != NULL) { + wbcMem->destructor(p); + } + free(wbcMem); return; } +char *wbcStrDup(const char *str) +{ + char *result; + size_t len; + + len = strlen(str); + result = (char *)wbcAllocateMemory(len+1, sizeof(char), NULL); + if (result == NULL) { + return NULL; + } + memcpy(result, str, len+1); + return result; +} + +static void wbcStringArrayDestructor(void *ptr) +{ + char **p = (char **)ptr; + while (*p != NULL) { + free(*p); + p += 1; + } +} + +const char **wbcAllocateStringArray(int num_strings) +{ + return (const char **)wbcAllocateMemory( + num_strings + 1, sizeof(const char *), + wbcStringArrayDestructor); +} + wbcErr wbcLibraryDetails(struct wbcLibraryDetails **_details) { - wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct wbcLibraryDetails *info; - info = talloc(NULL, struct wbcLibraryDetails); - BAIL_ON_PTR_ERROR(info, wbc_status); + info = (struct wbcLibraryDetails *)wbcAllocateMemory( + 1, sizeof(struct wbcLibraryDetails), NULL); + + if (info == NULL) { + return WBC_ERR_NO_MEMORY; + } info->major_version = WBCLIENT_MAJOR_VERSION; info->minor_version = WBCLIENT_MINOR_VERSION; - info->vendor_version = talloc_strdup(info, - WBCLIENT_VENDOR_VERSION); - BAIL_ON_PTR_ERROR(info->vendor_version, wbc_status); + info->vendor_version = WBCLIENT_VENDOR_VERSION; *_details = info; - info = NULL; - - wbc_status = WBC_ERR_SUCCESS; - -done: - talloc_free(info); - return wbc_status; + return WBC_ERR_SUCCESS; } diff --git a/nsswitch/libwbclient/wbclient.h b/nsswitch/libwbclient/wbclient.h index ac206909b0..c5f3b77ed8 100644 --- a/nsswitch/libwbclient/wbclient.h +++ b/nsswitch/libwbclient/wbclient.h @@ -65,9 +65,12 @@ const char *wbcErrorString(wbcErr error); * Added wbcGetSidAliases() * 0.4: Added wbcSidTypeString() * 0.5: Added wbcChangeTrustCredentials() + * 0.6: Made struct wbcInterfaceDetails char* members non-const + * 0.7: Added wbcSidToStringBuf() + * 0.8: Added wbcSidsToUnixIds() and wbcLookupSids() **/ #define WBCLIENT_MAJOR_VERSION 0 -#define WBCLIENT_MINOR_VERSION 5 +#define WBCLIENT_MINOR_VERSION 8 #define WBCLIENT_VENDOR_VERSION "Samba libwbclient" struct wbcLibraryDetails { uint16_t major_version; @@ -81,11 +84,11 @@ struct wbcLibraryDetails { **/ struct wbcInterfaceDetails { uint32_t interface_version; - const char *winbind_version; + char *winbind_version; char winbind_separator; - const char *netbios_name; - const char *netbios_domain; - const char *dns_domain; + char *netbios_name; + char *netbios_domain; + char *dns_domain; }; /* @@ -191,7 +194,6 @@ struct wbcDomainInfo { #define WBC_DOMINFO_TRUSTTYPE_IN_FOREST 0x00000002 #define WBC_DOMINFO_TRUSTTYPE_EXTERNAL 0x00000003 - /** * @brief Auth User Parameters **/ @@ -429,12 +431,23 @@ struct wbcUserPasswordPolicyInfo { **/ enum wbcPasswordChangeRejectReason { - WBC_PWD_CHANGE_REJECT_OTHER=0, - WBC_PWD_CHANGE_REJECT_TOO_SHORT=1, - WBC_PWD_CHANGE_REJECT_IN_HISTORY=2, - WBC_PWD_CHANGE_REJECT_COMPLEXITY=5 + WBC_PWD_CHANGE_NO_ERROR=0, + WBC_PWD_CHANGE_PASSWORD_TOO_SHORT=1, + WBC_PWD_CHANGE_PWD_IN_HISTORY=2, + WBC_PWD_CHANGE_USERNAME_IN_PASSWORD=3, + WBC_PWD_CHANGE_FULLNAME_IN_PASSWORD=4, + WBC_PWD_CHANGE_NOT_COMPLEX=5, + WBC_PWD_CHANGE_MACHINE_NOT_DEFAULT=6, + WBC_PWD_CHANGE_FAILED_BY_FILTER=7, + WBC_PWD_CHANGE_PASSWORD_TOO_LONG=8 }; +/* Note: this defines exist for compatibility reasons with existing code */ +#define WBC_PWD_CHANGE_REJECT_OTHER WBC_PWD_CHANGE_NO_ERROR +#define WBC_PWD_CHANGE_REJECT_TOO_SHORT WBC_PWD_CHANGE_PASSWORD_TOO_SHORT +#define WBC_PWD_CHANGE_REJECT_IN_HISTORY WBC_PWD_CHANGE_PWD_IN_HISTORY +#define WBC_PWD_CHANGE_REJECT_COMPLEXITY WBC_PWD_CHANGE_NOT_COMPLEX + /** * @brief Logoff User Parameters **/ @@ -518,6 +531,19 @@ void wbcFreeMemory(void*); */ const char* wbcSidTypeString(enum wbcSidType type); +#define WBC_SID_STRING_BUFLEN (15*11+25) + +/* + * @brief Print a sid into a buffer + * + * @param sid Binary Security Identifier + * @param buf Target buffer + * @param buflen Target buffer length + * + * @return Resulting string length. + */ +int wbcSidToStringBuf(const struct wbcDomainSid *sid, char *buf, int buflen); + /** * @brief Convert a binary SID to a character string * @@ -611,6 +637,16 @@ wbcErr wbcLookupSid(const struct wbcDomainSid *sid, char **name, enum wbcSidType *name_type); +struct wbcTranslatedName { + enum wbcSidType type; + char *name; + int domain_index; +}; + +wbcErr wbcLookupSids(const struct wbcDomainSid *sids, int num_sids, + struct wbcDomainInfo **domains, int *num_domains, + struct wbcTranslatedName **names); + /** * @brief Translate a collection of RIDs within a domain to names */ @@ -757,6 +793,35 @@ wbcErr wbcGidToSid(gid_t gid, wbcErr wbcQueryGidToSid(gid_t gid, struct wbcDomainSid *sid); +enum wbcIdType { + WBC_ID_TYPE_NOT_SPECIFIED, + WBC_ID_TYPE_UID, + WBC_ID_TYPE_GID +}; + +union wbcUnixIdContainer { + uid_t uid; + gid_t gid; +}; + +struct wbcUnixId { + enum wbcIdType type; + union wbcUnixIdContainer id; +}; + +/** + * @brief Convert a list of sids to unix ids + * + * @param sids Pointer to an array of SIDs to convert + * @param num_sids Number of SIDs + * @param ids Preallocated output array for translated IDs + * + * @return #wbcErr + * + **/ +wbcErr wbcSidsToUnixIds(const struct wbcDomainSid *sids, uint32_t num_sids, + struct wbcUnixId *ids); + /** * @brief Obtain a new uid from Winbind * @@ -782,6 +847,9 @@ wbcErr wbcAllocateGid(gid_t *pgid); * @param *sid Pointer to the sid of the diresired mapping. * * @return #wbcErr + * + * @deprecated This method is not impemented any more and should + * be removed in the next major version change. **/ wbcErr wbcSetUidMapping(uid_t uid, const struct wbcDomainSid *sid); @@ -792,6 +860,9 @@ wbcErr wbcSetUidMapping(uid_t uid, const struct wbcDomainSid *sid); * @param *sid Pointer to the sid of the diresired mapping. * * @return #wbcErr + * + * @deprecated This method is not impemented any more and should + * be removed in the next major version change. **/ wbcErr wbcSetGidMapping(gid_t gid, const struct wbcDomainSid *sid); @@ -802,6 +873,9 @@ wbcErr wbcSetGidMapping(gid_t gid, const struct wbcDomainSid *sid); * @param *sid Pointer to the sid of the mapping to remove. * * @return #wbcErr + * + * @deprecated This method is not impemented any more and should + * be removed in the next major version change. **/ wbcErr wbcRemoveUidMapping(uid_t uid, const struct wbcDomainSid *sid); @@ -812,6 +886,9 @@ wbcErr wbcRemoveUidMapping(uid_t uid, const struct wbcDomainSid *sid); * @param *sid Pointer to the sid of the mapping to remove. * * @return #wbcErr + * + * @deprecated This method is not impemented any more and should + * be removed in the next major version change. **/ wbcErr wbcRemoveGidMapping(gid_t gid, const struct wbcDomainSid *sid); @@ -821,6 +898,9 @@ wbcErr wbcRemoveGidMapping(gid_t gid, const struct wbcDomainSid *sid); * @param uid_hwm The new uid highwater mark value * * @return #wbcErr + * + * @deprecated This method is not impemented any more and should + * be removed in the next major version change. **/ wbcErr wbcSetUidHwm(uid_t uid_hwm); @@ -830,6 +910,9 @@ wbcErr wbcSetUidHwm(uid_t uid_hwm); * @param gid_hwm The new gid highwater mark value * * @return #wbcErr + * + * @deprecated This method is not impemented any more and should + * be removed in the next major version change. **/ wbcErr wbcSetGidHwm(gid_t gid_hwm); @@ -970,13 +1053,28 @@ wbcErr wbcGetGroups(const char *account, /** * @brief Lookup the current status of a trusted domain * - * @param domain Domain to query - * @param *info Pointer to returned domain_info struct + * @param domain The domain to query + * + * @param dinfo A pointer to store the returned domain_info struct. * * @return #wbcErr **/ wbcErr wbcDomainInfo(const char *domain, - struct wbcDomainInfo **info); + struct wbcDomainInfo **dinfo); + +/** + * @brief Lookup the currently contacted DCs + * + * @param domain The domain to query + * + * @param num_dcs Number of DCs currently known + * @param dc_names Names of the currently known DCs + * @param dc_ips IP addresses of the currently known DCs + * + * @return #wbcErr + **/ +wbcErr wbcDcInfo(const char *domain, size_t *num_dcs, + const char ***dc_names, const char ***dc_ips); /** * @brief Enumerate the domain trusts known by Winbind diff --git a/nsswitch/libwbclient/wbclient_internal.h b/nsswitch/libwbclient/wbclient_internal.h index 5ce820785e..31f413057e 100644 --- a/nsswitch/libwbclient/wbclient_internal.h +++ b/nsswitch/libwbclient/wbclient_internal.h @@ -32,4 +32,10 @@ wbcErr wbcRequestResponsePriv(int cmd, struct winbindd_request *request, struct winbindd_response *response); +void *wbcAllocateMemory(size_t nelem, size_t elsize, + void (*destructor)(void *ptr)); + +char *wbcStrDup(const char *str); +const char **wbcAllocateStringArray(int num_strings); + #endif /* _WBCLIENT_INTERNAL_H */ diff --git a/nsswitch/libwbclient/wscript_build b/nsswitch/libwbclient/wscript_build new file mode 100644 index 0000000000..d9255159d0 --- /dev/null +++ b/nsswitch/libwbclient/wscript_build @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +bld.SAMBA_LIBRARY('wbclient', + source='wbc_guid.c wbc_idmap.c wbclient.c wbc_pam.c wbc_pwd.c wbc_sid.c wbc_util.c', + deps='winbind-client', + public_headers='wbclient.h', + vnum='0' + ) diff --git a/nsswitch/nsstest.c b/nsswitch/nsstest.c index 26f816f5d1..d84e028513 100644 --- a/nsswitch/nsstest.c +++ b/nsswitch/nsstest.c @@ -2,6 +2,7 @@ Unix SMB/CIFS implementation. nss tester for winbindd Copyright (C) Andrew Tridgell 2001 + Copyright (C) Tim Potter 2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,8 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "includes.h" - +#include "replace.h" #include "nsswitch/nsstest.h" static const char *so_path = "/lib/libnss_winbind.so"; @@ -29,11 +29,13 @@ static int total_errors; static void *find_fn(const char *name) { - char s[1024]; + char *s; static void *h; void *res; - snprintf(s,sizeof(s), "_nss_%s_%s", nss_name, name); + if (asprintf(&s, "_nss_%s_%s", nss_name, name) < 0) { + exit(1); + } if (!h) { h = dlopen(so_path, RTLD_LAZY); @@ -45,8 +47,11 @@ static void *find_fn(const char *name) res = dlsym(h, s); if (!res) { printf("Can't find function %s\n", s); + total_errors++; + free(s); return NULL; } + free(s); return res; } @@ -61,11 +66,16 @@ static void report_nss_error(const char *who, NSS_STATUS status) static struct passwd *nss_getpwent(void) { NSS_STATUS (*_nss_getpwent_r)(struct passwd *, char *, - size_t , int *) = find_fn("getpwent_r"); + size_t , int *) = + (NSS_STATUS (*)(struct passwd *, char *, + size_t, int *))find_fn("getpwent_r"); static struct passwd pwd; static char buf[1000]; NSS_STATUS status; + if (!_nss_getpwent_r) + return NULL; + status = _nss_getpwent_r(&pwd, buf, sizeof(buf), &nss_errno); if (status == NSS_STATUS_NOTFOUND) { return NULL; @@ -80,11 +90,16 @@ static struct passwd *nss_getpwent(void) static struct passwd *nss_getpwnam(const char *name) { NSS_STATUS (*_nss_getpwnam_r)(const char *, struct passwd *, char *, - size_t , int *) = find_fn("getpwnam_r"); + size_t , int *) = + (NSS_STATUS (*)(const char *, struct passwd *, char *, + size_t, int *))find_fn("getpwnam_r"); static struct passwd pwd; static char buf[1000]; NSS_STATUS status; + if (!_nss_getpwnam_r) + return NULL; + status = _nss_getpwnam_r(name, &pwd, buf, sizeof(buf), &nss_errno); if (status == NSS_STATUS_NOTFOUND) { return NULL; @@ -99,11 +114,16 @@ static struct passwd *nss_getpwnam(const char *name) static struct passwd *nss_getpwuid(uid_t uid) { NSS_STATUS (*_nss_getpwuid_r)(uid_t , struct passwd *, char *, - size_t , int *) = find_fn("getpwuid_r"); + size_t , int *) = + (NSS_STATUS (*)(uid_t, struct passwd *, char *, + size_t, int *))find_fn("getpwuid_r"); static struct passwd pwd; static char buf[1000]; NSS_STATUS status; + if (!_nss_getpwuid_r) + return NULL; + status = _nss_getpwuid_r(uid, &pwd, buf, sizeof(buf), &nss_errno); if (status == NSS_STATUS_NOTFOUND) { return NULL; @@ -117,8 +137,13 @@ static struct passwd *nss_getpwuid(uid_t uid) static void nss_setpwent(void) { - NSS_STATUS (*_nss_setpwent)(void) = find_fn("setpwent"); + NSS_STATUS (*_nss_setpwent)(void) = + (NSS_STATUS(*)(void))find_fn("setpwent"); NSS_STATUS status; + + if (!_nss_setpwent) + return; + status = _nss_setpwent(); if (status != NSS_STATUS_SUCCESS) { report_nss_error("setpwent", status); @@ -127,8 +152,13 @@ static void nss_setpwent(void) static void nss_endpwent(void) { - NSS_STATUS (*_nss_endpwent)(void) = find_fn("endpwent"); + NSS_STATUS (*_nss_endpwent)(void) = + (NSS_STATUS (*)(void))find_fn("endpwent"); NSS_STATUS status; + + if (!_nss_endpwent) + return; + status = _nss_endpwent(); if (status != NSS_STATUS_SUCCESS) { report_nss_error("endpwent", status); @@ -139,26 +169,37 @@ static void nss_endpwent(void) static struct group *nss_getgrent(void) { NSS_STATUS (*_nss_getgrent_r)(struct group *, char *, - size_t , int *) = find_fn("getgrent_r"); + size_t , int *) = + (NSS_STATUS (*)(struct group *, char *, + size_t, int *))find_fn("getgrent_r"); static struct group grp; static char *buf; static int buflen = 1024; NSS_STATUS status; - if (!buf) buf = malloc_array_p(char, buflen); + if (!_nss_getgrent_r) + return NULL; + + if (!buf) + buf = (char *)malloc(buflen); again: status = _nss_getgrent_r(&grp, buf, buflen, &nss_errno); if (status == NSS_STATUS_TRYAGAIN) { buflen *= 2; - buf = realloc_p(buf, char, buflen); + buf = (char *)realloc(buf, buflen); + if (!buf) { + return NULL; + } goto again; } if (status == NSS_STATUS_NOTFOUND) { + free(buf); return NULL; } if (status != NSS_STATUS_SUCCESS) { report_nss_error("getgrent", status); + free(buf); return NULL; } return &grp; @@ -167,25 +208,36 @@ again: static struct group *nss_getgrnam(const char *name) { NSS_STATUS (*_nss_getgrnam_r)(const char *, struct group *, char *, - size_t , int *) = find_fn("getgrnam_r"); + size_t , int *) = + (NSS_STATUS (*)(const char *, struct group *, char *, + size_t, int *))find_fn("getgrnam_r"); static struct group grp; static char *buf; static int buflen = 1000; NSS_STATUS status; - if (!buf) buf = malloc_array_p(char, buflen); + if (!_nss_getgrnam_r) + return NULL; + + if (!buf) + buf = (char *)malloc(buflen); again: status = _nss_getgrnam_r(name, &grp, buf, buflen, &nss_errno); if (status == NSS_STATUS_TRYAGAIN) { buflen *= 2; - buf = realloc_p(buf, char, buflen); + buf = (char *)realloc(buf, buflen); + if (!buf) { + return NULL; + } goto again; } if (status == NSS_STATUS_NOTFOUND) { + free(buf); return NULL; } if (status != NSS_STATUS_SUCCESS) { report_nss_error("getgrnam", status); + free(buf); return NULL; } return &grp; @@ -194,25 +246,37 @@ again: static struct group *nss_getgrgid(gid_t gid) { NSS_STATUS (*_nss_getgrgid_r)(gid_t , struct group *, char *, - size_t , int *) = find_fn("getgrgid_r"); + size_t , int *) = + (NSS_STATUS (*)(gid_t, struct group *, char *, + size_t, int *))find_fn("getgrgid_r"); static struct group grp; static char *buf; static int buflen = 1000; NSS_STATUS status; - if (!buf) buf = malloc_array_p(char, buflen); + if (!_nss_getgrgid_r) + return NULL; + + if (!buf) + buf = (char *)malloc(buflen); + again: status = _nss_getgrgid_r(gid, &grp, buf, buflen, &nss_errno); if (status == NSS_STATUS_TRYAGAIN) { buflen *= 2; - buf = realloc_p(buf, char, buflen); + buf = (char *)realloc(buf, buflen); + if (!buf) { + return NULL; + } goto again; } if (status == NSS_STATUS_NOTFOUND) { + free(buf); return NULL; } if (status != NSS_STATUS_SUCCESS) { report_nss_error("getgrgid", status); + free(buf); return NULL; } return &grp; @@ -220,8 +284,13 @@ again: static void nss_setgrent(void) { - NSS_STATUS (*_nss_setgrent)(void) = find_fn("setgrent"); + NSS_STATUS (*_nss_setgrent)(void) = + (NSS_STATUS (*)(void))find_fn("setgrent"); NSS_STATUS status; + + if (!_nss_setgrent) + return; + status = _nss_setgrent(); if (status != NSS_STATUS_SUCCESS) { report_nss_error("setgrent", status); @@ -230,8 +299,13 @@ static void nss_setgrent(void) static void nss_endgrent(void) { - NSS_STATUS (*_nss_endgrent)(void) = find_fn("endgrent"); + NSS_STATUS (*_nss_endgrent)(void) = + (NSS_STATUS (*)(void))find_fn("endgrent"); NSS_STATUS status; + + if (!_nss_endgrent) + return; + status = _nss_endgrent(); if (status != NSS_STATUS_SUCCESS) { report_nss_error("endgrent", status); @@ -242,10 +316,13 @@ static int nss_initgroups(char *user, gid_t group, gid_t **groups, long int *sta { NSS_STATUS (*_nss_initgroups)(char *, gid_t , long int *, long int *, gid_t **, long int , int *) = - find_fn("initgroups_dyn"); + (NSS_STATUS (*)(char *, gid_t, long int *, + long int *, gid_t **, + long int, int *))find_fn("initgroups_dyn"); NSS_STATUS status; - if (!_nss_initgroups) return NSS_STATUS_UNAVAIL; + if (!_nss_initgroups) + return NSS_STATUS_UNAVAIL; status = _nss_initgroups(user, group, start, size, groups, 0, &nss_errno); if (status != NSS_STATUS_SUCCESS) { @@ -256,11 +333,11 @@ static int nss_initgroups(char *user, gid_t group, gid_t **groups, long int *sta static void print_passwd(struct passwd *pwd) { - printf("%s:%s:%d:%d:%s:%s:%s\n", + printf("%s:%s:%lu:%lu:%s:%s:%s\n", pwd->pw_name, pwd->pw_passwd, - pwd->pw_uid, - pwd->pw_gid, + (unsigned long)pwd->pw_uid, + (unsigned long)pwd->pw_gid, pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell); @@ -269,10 +346,10 @@ static void print_passwd(struct passwd *pwd) static void print_group(struct group *grp) { int i; - printf("%s:%s:%d: ", + printf("%s:%s:%lu:", grp->gr_name, grp->gr_passwd, - grp->gr_gid); + (unsigned long)grp->gr_gid); if (!grp->gr_mem[0]) { printf("\n"); @@ -280,7 +357,7 @@ static void print_group(struct group *grp) } for (i=0; grp->gr_mem[i+1]; i++) { - printf("%s, ", grp->gr_mem[i]); + printf("%s,", grp->gr_mem[i]); } printf("%s\n", grp->gr_mem[i]); } @@ -293,7 +370,7 @@ static void nss_test_initgroups(char *name, gid_t gid) int i; NSS_STATUS status; - groups = (gid_t *)malloc_array_p(gid_t, size); + groups = (gid_t *)malloc(size); groups[0] = gid; status = nss_initgroups(name, gid, &groups, &start, &size); @@ -303,9 +380,9 @@ static void nss_test_initgroups(char *name, gid_t gid) } for (i=0; i<start-1; i++) { - printf("%d, ", groups[i]); + printf("%lu, ", (unsigned long)groups[i]); } - printf("%d\n", groups[i]); + printf("%lu\n", (unsigned long)groups[i]); } diff --git a/nsswitch/nsstest.m4 b/nsswitch/nsstest.m4 deleted file mode 100644 index 37596489c0..0000000000 --- a/nsswitch/nsstest.m4 +++ /dev/null @@ -1,8 +0,0 @@ -case "$host_os" in - *linux*) - SMB_ENABLE(nsstest,YES) - ;; - *) - SMB_ENABLE(nsstest,NO) - ;; -esac diff --git a/nsswitch/pam_winbind.c b/nsswitch/pam_winbind.c index b80203674b..7005c25fae 100644 --- a/nsswitch/pam_winbind.c +++ b/nsswitch/pam_winbind.c @@ -156,7 +156,7 @@ static inline void textdomain_init(void); static inline void textdomain_init(void) { if (!initialized) { - bindtextdomain(MODULE_NAME, dyn_LOCALEDIR); + bindtextdomain(MODULE_NAME, LOCALEDIR); initialized = 1; } return; @@ -1077,12 +1077,11 @@ static bool winbind_name_to_sid_string(struct pwb_context *ctx, char *sid_list_buffer, int sid_list_buffer_size) { - const char* sid_string = NULL; - char *sid_str = NULL; + char sid_string[WBC_SID_STRING_BUFLEN]; /* lookup name? */ if (IS_SID_STRING(name)) { - sid_string = name; + strlcpy(sid_string, name, sizeof(sid_string)); } else { wbcErr wbc_status; struct wbcDomainSid sid; @@ -1098,21 +1097,13 @@ static bool winbind_name_to_sid_string(struct pwb_context *ctx, return false; } - wbc_status = wbcSidToString(&sid, &sid_str); - if (!WBC_ERROR_IS_OK(wbc_status)) { - return false; - } - - sid_string = sid_str; + wbcSidToStringBuf(&sid, sid_string, sizeof(sid_string)); } if (!safe_append_string(sid_list_buffer, sid_string, sid_list_buffer_size)) { - wbcFreeMemory(sid_str); return false; } - - wbcFreeMemory(sid_str); return true; } @@ -1144,7 +1135,7 @@ static bool winbind_name_list_to_sid_string_list(struct pwb_context *ctx, } search_location = name_list; - while ((comma = strstr(search_location, ",")) != NULL) { + while ((comma = strchr(search_location, ',')) != NULL) { current_name = strndup(search_location, comma - search_location); if (NULL == current_name) { @@ -1199,10 +1190,8 @@ static bool winbind_name_list_to_sid_string_list(struct pwb_context *ctx, * It is malformated parameter here, overwrite the last ','. */ len = strlen(sid_list_buffer); - if (len) { - if (sid_list_buffer[len - 1] == ',') { - sid_list_buffer[len - 1] = '\0'; - } + if ((len != 0) && (sid_list_buffer[len - 1] == ',')) { + sid_list_buffer[len - 1] = '\0'; } } @@ -1434,12 +1423,12 @@ static void _pam_warn_krb5_failure(struct pwb_context *ctx, static bool _pam_check_remark_auth_err(struct pwb_context *ctx, const struct wbcAuthErrorInfo *e, const char *nt_status_string, - int *pam_error) + int *pam_err) { const char *ntstatus = NULL; const char *error_string = NULL; - if (!e || !pam_error) { + if (!e || !pam_err) { return false; } @@ -1453,18 +1442,18 @@ static bool _pam_check_remark_auth_err(struct pwb_context *ctx, error_string = _get_ntstatus_error_string(nt_status_string); if (error_string) { _make_remark(ctx, PAM_ERROR_MSG, error_string); - *pam_error = e->pam_error; + *pam_err = e->pam_error; return true; } if (e->display_string) { - _make_remark(ctx, PAM_ERROR_MSG, e->display_string); - *pam_error = e->pam_error; + _make_remark(ctx, PAM_ERROR_MSG, _(e->display_string)); + *pam_err = e->pam_error; return true; } _make_remark(ctx, PAM_ERROR_MSG, nt_status_string); - *pam_error = e->pam_error; + *pam_err = e->pam_error; return true; } @@ -1901,9 +1890,7 @@ static int winbind_auth_request(struct pwb_context *ctx, } done: - if (logon.blobs) { - wbcFreeMemory(logon.blobs); - } + wbcFreeMemory(logon.blobs); if (info && info->blobs && !p_info) { wbcFreeMemory(info->blobs); } @@ -2000,22 +1987,22 @@ static int winbind_chauthtok_request(struct pwb_context *ctx, switch (reject_reason) { case -1: break; - case WBC_PWD_CHANGE_REJECT_OTHER: + case WBC_PWD_CHANGE_NO_ERROR: if ((min_pwd_age > 0) && (pwd_last_set + min_pwd_age > time(NULL))) { PAM_WB_REMARK_DIRECT(ctx, "NT_STATUS_PWD_TOO_RECENT"); } break; - case WBC_PWD_CHANGE_REJECT_TOO_SHORT: + case WBC_PWD_CHANGE_PASSWORD_TOO_SHORT: PAM_WB_REMARK_DIRECT(ctx, "NT_STATUS_PWD_TOO_SHORT"); break; - case WBC_PWD_CHANGE_REJECT_IN_HISTORY: + case WBC_PWD_CHANGE_PWD_IN_HISTORY: PAM_WB_REMARK_DIRECT(ctx, "NT_STATUS_PWD_HISTORY_CONFLICT"); break; - case WBC_PWD_CHANGE_REJECT_COMPLEXITY: + case WBC_PWD_CHANGE_NOT_COMPLEX: _make_remark(ctx, PAM_ERROR_MSG, _("Password does not meet " "complexity requirements")); @@ -2424,7 +2411,7 @@ static char* winbind_upn_to_username(struct pwb_context *ctx, wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct wbcDomainSid sid; enum wbcSidType type; - char *domain; + char *domain = NULL; char *name; char *p; diff --git a/nsswitch/pam_winbind.h b/nsswitch/pam_winbind.h index 25d673e231..0d9529e726 100644 --- a/nsswitch/pam_winbind.h +++ b/nsswitch/pam_winbind.h @@ -1,15 +1,60 @@ +/* + * Copyright (c) Andrew Tridgell <tridge@samba.org> 2000 + * Copyright (c) Tim Potter <tpot@samba.org> 2000 + * Copyright (c) Andrew Bartlettt <abartlet@samba.org> 2002 + * Copyright (c) Guenther Deschner <gd@samba.org> 2005-2008 + * Copyright (c) Jan Rêkorajski 1999. + * Copyright (c) Andrew G. Morgan 1996-8. + * Copyright (c) Alex O. Yuriev, 1996. + * Copyright (c) Cristian Gafton 1996. + * Copyright (C) Elliot Lee <sopwith@redhat.com> 1996, Red Hat Software. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + /* pam_winbind header file (Solaris needs some macros from Linux for common PAM code) Shirish Kalele 2000 */ +#ifndef _NSSWITCH_PAM_WINBIND_H_ +#define _NSSWITCH_PAM_WINBIND_H_ + #include "../lib/replace/replace.h" #include "system/syslog.h" #include "system/time.h" #include <talloc.h> #include "libwbclient/wbclient.h" -#include "localedir.h" #define MODULE_NAME "pam_winbind" #define PAM_SM_AUTH @@ -176,3 +221,5 @@ struct pwb_context { #endif #define TALLOC_ZERO_P(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type) #define TALLOC_P(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type) + +#endif /* _NSSWITCH_PAM_WINBIND_H_ */ diff --git a/nsswitch/tests/test_wbinfo.sh b/nsswitch/tests/test_wbinfo.sh index 8d8f116e70..b344f718c5 100755 --- a/nsswitch/tests/test_wbinfo.sh +++ b/nsswitch/tests/test_wbinfo.sh @@ -15,7 +15,7 @@ shift 4 failed=0 samba4bindir="$BUILDDIR/bin" -wbinfo="$samba4bindir/wbinfo$EXEEXT" +wbinfo="$VALGRIND $samba4bindir/wbinfo$EXEEXT" . `dirname $0`/../../testprogs/blackbox/subunit.sh @@ -163,6 +163,7 @@ if test x$own_domain = x$DOMAIN; then else echo "Own domain reported as $own_domain instead of $DOMAIN" echo "failure: wbinfo --own-domain against $TARGET check output" + failed=`expr $failed + 1` fi # this does not work @@ -173,12 +174,21 @@ testit "wbinfo -D against $TARGET" $wbinfo -D $DOMAIN || failed=`expr $failed + testit "wbinfo -i against $TARGET" $wbinfo -i "$DOMAIN/$USERNAME" || failed=`expr $failed + 1` -testit "wbinfo --uid-info against $TARGET" $wbinfo --uid-info $admin_uid +testit "wbinfo --uid-info against $TARGET" $wbinfo --uid-info $admin_uid || failed=`expr $failed + 1` -# this does not work -knownfail "wbinfo --group-info against $TARGET" $wbinfo --group-info "S-1-22-2-0" -knownfail "wbinfo --gid-info against $TARGET" $wbinfo --gid-info 30001 -knownfail "wbinfo -r against $TARGET" $wbinfo -r "$DOMAIN/$USERNAME" +echo "test: wbinfo --group-info against $TARGET" +rawgid=`$wbinfo --group-info "Domain admins" | sed 's/.*:\([0-9][0-9]*\):/\1/'` +if test x$? = x0; then + echo "success: wbinfo --group-info against $TARGET" +else + echo "failure: wbinfo --group-info against $TARGET" + failed=`expr $failed + 1` +fi + +gid=`echo $rawgid | sed 's/.*:\([0-9][0-9]*\):/\1/'` +testit "wbinfo --gid-info against $TARGET" $wbinfo --gid-info $gid || failed=`expr $failed + 1` + +testit "wbinfo -r against $TARGET" $wbinfo -r "$DOMAIN/$USERNAME" || failed=`expr $failed + 1` testit "wbinfo --user-domgroups against $TARGET" $wbinfo --user-domgroups $admin_sid || failed=`expr $failed + 1` diff --git a/nsswitch/wb_common.c b/nsswitch/wb_common.c index def41d5cea..dcfc8a5156 100644 --- a/nsswitch/wb_common.c +++ b/nsswitch/wb_common.c @@ -22,6 +22,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "replace.h" +#include "system/select.h" #include "winbind_client.h" /* Global variables. These are effectively the client state information */ @@ -41,7 +43,8 @@ void winbindd_free_response(struct winbindd_response *response) /* Initialise a request structure */ -void winbindd_init_request(struct winbindd_request *request, int request_type) +static void winbindd_init_request(struct winbindd_request *request, + int request_type) { request->length = sizeof(struct winbindd_request); @@ -64,7 +67,7 @@ static void init_response(struct winbindd_response *response) #if HAVE_FUNCTION_ATTRIBUTE_DESTRUCTOR __attribute__((destructor)) #endif -void winbind_close_sock(void) +static void winbind_close_sock(void) { if (winbindd_fd != -1) { close(winbindd_fd); @@ -232,8 +235,7 @@ static int winbind_named_pipe_sock(const char *dir) for (wait_time = 0; connect(fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1; wait_time += slept) { - struct timeval tv; - fd_set w_fds; + struct pollfd pfd; int ret; int connect_errno = 0; socklen_t errnosize; @@ -243,16 +245,10 @@ static int winbind_named_pipe_sock(const char *dir) switch (errno) { case EINPROGRESS: - FD_ZERO(&w_fds); - if (fd < 0 || fd >= FD_SETSIZE) { - errno = EBADF; - goto error_out; - } - FD_SET(fd, &w_fds); - tv.tv_sec = CONNECT_TIMEOUT - wait_time; - tv.tv_usec = 0; + pfd.fd = fd; + pfd.events = POLLOUT; - ret = select(fd + 1, NULL, &w_fds, NULL, &tv); + ret = poll(&pfd, 1, (CONNECT_TIMEOUT - wait_time) * 1000); if (ret > 0) { errnosize = sizeof(connect_errno); @@ -370,7 +366,8 @@ static int winbind_open_pipe_sock(int recursing, int need_priv) /* Write data to winbindd socket */ -int winbind_write_sock(void *buffer, int count, int recursing, int need_priv) +static int winbind_write_sock(void *buffer, int count, int recursing, + int need_priv) { int result, nwritten; @@ -388,53 +385,46 @@ int winbind_write_sock(void *buffer, int count, int recursing, int need_priv) nwritten = 0; while(nwritten < count) { - struct timeval tv; - fd_set r_fds; + struct pollfd pfd; + int ret; /* Catch pipe close on other end by checking if a read() - call would not block by calling select(). */ + call would not block by calling poll(). */ - FD_ZERO(&r_fds); - if (winbindd_fd < 0 || winbindd_fd >= FD_SETSIZE) { - errno = EBADF; - winbind_close_sock(); - return -1; - } - FD_SET(winbindd_fd, &r_fds); - ZERO_STRUCT(tv); + pfd.fd = winbindd_fd; + pfd.events = POLLIN|POLLHUP; - if (select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv) == -1) { + ret = poll(&pfd, 1, 0); + if (ret == -1) { winbind_close_sock(); - return -1; /* Select error */ + return -1; /* poll error */ } /* Write should be OK if fd not available for reading */ - if (!FD_ISSET(winbindd_fd, &r_fds)) { + if ((ret == 1) && (pfd.revents & (POLLIN|POLLHUP|POLLERR))) { - /* Do the write */ - - result = write(winbindd_fd, - (char *)buffer + nwritten, - count - nwritten); - - if ((result == -1) || (result == 0)) { + /* Pipe has closed on remote end */ - /* Write failed */ + winbind_close_sock(); + goto restart; + } - winbind_close_sock(); - return -1; - } + /* Do the write */ - nwritten += result; + result = write(winbindd_fd, + (char *)buffer + nwritten, + count - nwritten); - } else { + if ((result == -1) || (result == 0)) { - /* Pipe has closed on remote end */ + /* Write failed */ winbind_close_sock(); - goto restart; + return -1; } + + nwritten += result; } return nwritten; @@ -442,10 +432,10 @@ int winbind_write_sock(void *buffer, int count, int recursing, int need_priv) /* Read data from winbindd socket */ -int winbind_read_sock(void *buffer, int count) +static int winbind_read_sock(void *buffer, int count) { int nread = 0; - int total_time = 0, selret; + int total_time = 0; if (winbindd_fd == -1) { return -1; @@ -453,29 +443,24 @@ int winbind_read_sock(void *buffer, int count) /* Read data from socket */ while(nread < count) { - struct timeval tv; - fd_set r_fds; + struct pollfd pfd; + int ret; /* Catch pipe close on other end by checking if a read() - call would not block by calling select(). */ + call would not block by calling poll(). */ + + pfd.fd = winbindd_fd; + pfd.events = POLLIN|POLLHUP; - FD_ZERO(&r_fds); - if (winbindd_fd < 0 || winbindd_fd >= FD_SETSIZE) { - errno = EBADF; - winbind_close_sock(); - return -1; - } - FD_SET(winbindd_fd, &r_fds); - ZERO_STRUCT(tv); /* Wait for 5 seconds for a reply. May need to parameterise this... */ - tv.tv_sec = 5; - if ((selret = select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv)) == -1) { + ret = poll(&pfd, 1, 5000); + if (ret == -1) { winbind_close_sock(); - return -1; /* Select error */ + return -1; /* poll error */ } - if (selret == 0) { + if (ret == 0) { /* Not ready for read yet... */ if (total_time >= 30) { /* Timeout */ @@ -486,7 +471,7 @@ int winbind_read_sock(void *buffer, int count) continue; } - if (FD_ISSET(winbindd_fd, &r_fds)) { + if ((ret == 1) && (pfd.revents & (POLLIN|POLLHUP|POLLERR))) { /* Do the Read */ @@ -513,7 +498,7 @@ int winbind_read_sock(void *buffer, int count) /* Read reply */ -int winbindd_read_reply(struct winbindd_response *response) +static int winbindd_read_reply(struct winbindd_response *response) { int result1, result2 = 0; @@ -529,6 +514,10 @@ int winbindd_read_reply(struct winbindd_response *response) return -1; } + if (response->length < sizeof(struct winbindd_response)) { + return -1; + } + /* We actually send the pointer value of the extra_data field from the server. This has no meaning in the client's address space so we clear it out. */ @@ -682,26 +671,3 @@ NSS_STATUS winbindd_priv_request_response(int req_type, return status; } - -/************************************************************************* - ************************************************************************/ - -const char *nss_err_str(NSS_STATUS ret) -{ - switch (ret) { - case NSS_STATUS_TRYAGAIN: - return "NSS_STATUS_TRYAGAIN"; - case NSS_STATUS_SUCCESS: - return "NSS_STATUS_SUCCESS"; - case NSS_STATUS_NOTFOUND: - return "NSS_STATUS_NOTFOUND"; - case NSS_STATUS_UNAVAIL: - return "NSS_STATUS_UNAVAIL"; -#ifdef NSS_STATUS_RETURN - case NSS_STATUS_RETURN: - return "NSS_STATUS_RETURN"; -#endif - default: - return "UNKNOWN RETURN CODE!!!!!!!"; - } -} diff --git a/nsswitch/libwbclient/wb_reqtrans.c b/nsswitch/wb_reqtrans.c index 6dc429bb7d..779ef52a92 100644 --- a/nsswitch/libwbclient/wb_reqtrans.c +++ b/nsswitch/wb_reqtrans.c @@ -32,7 +32,7 @@ #include "lib/util/tevent_unix.h" #include "nsswitch/winbind_struct_protocol.h" #include "nsswitch/libwbclient/wbclient.h" -#include "nsswitch/libwbclient/wbc_async.h" +#include "nsswitch/wb_reqtrans.h" /* can't use DEBUG here... */ #define DEBUG(a,b) diff --git a/nsswitch/libwbclient/wbc_async.h b/nsswitch/wb_reqtrans.h index 76e02cadf2..941edf659a 100644 --- a/nsswitch/libwbclient/wbc_async.h +++ b/nsswitch/wb_reqtrans.h @@ -21,46 +21,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _WBC_ASYNC_H_ -#define _WBC_ASYNC_H_ +#ifndef _WB_REQTRANS_H_ +#define _WB_REQTRANS_H_ #include <talloc.h> #include <tevent.h> -#include "nsswitch/libwbclient/wbclient.h" - -struct wb_context; -struct winbindd_request; -struct winbindd_response; - -enum wbcDebugLevel { - WBC_DEBUG_FATAL, - WBC_DEBUG_ERROR, - WBC_DEBUG_WARNING, - WBC_DEBUG_TRACE -}; - -struct tevent_req *wb_trans_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct wb_context *wb_ctx, bool need_priv, - struct winbindd_request *wb_req); -wbcErr wb_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, - struct winbindd_response **presponse); -struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx, const char* dir); -int wbcSetDebug(struct wb_context *wb_ctx, - void (*debug)(void *context, - enum wbcDebugLevel level, - const char *fmt, - va_list ap) PRINTF_ATTRIBUTE(3,0), - void *context); -int wbcSetDebugStderr(struct wb_context *wb_ctx); -void wbcDebug(struct wb_context *wb_ctx, enum wbcDebugLevel level, - const char *fmt, ...) PRINTF_ATTRIBUTE(3,0); - -/* Definitions from wb_reqtrans.c */ -wbcErr map_wbc_err_from_errno(int error); - -bool tevent_req_is_wbcerr(struct tevent_req *req, wbcErr *pwbc_err); -wbcErr tevent_req_simple_recv_wbcerr(struct tevent_req *req); +#include "nsswitch/winbind_struct_protocol.h" struct tevent_req *wb_req_read_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, @@ -92,4 +58,4 @@ struct tevent_req *wb_simple_trans_send(TALLOC_CTX *mem_ctx, int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, struct winbindd_response **presponse, int *err); -#endif /*_WBC_ASYNC_H_*/ +#endif /*_WB_REQTRANS_H_*/ diff --git a/nsswitch/wbinfo.c b/nsswitch/wbinfo.c index a43ce8f4c9..ac07175022 100644 --- a/nsswitch/wbinfo.c +++ b/nsswitch/wbinfo.c @@ -22,11 +22,12 @@ */ #include "includes.h" +#include "popt_common.h" #include "winbind_client.h" #include "libwbclient/wbclient.h" #include "lib/popt/popt.h" #include "../libcli/auth/libcli_auth.h" -#if !(_SAMBA_VERSION_) < 4 +#if (_SAMBA_BUILD_) >= 4 #include "lib/cmdline/popt_common.h" #endif @@ -47,7 +48,7 @@ static struct wbcInterfaceDetails *init_interface_details(void) wbc_status = wbcInterfaceDetails(&details); if (!WBC_ERROR_IS_OK(wbc_status)) { d_fprintf(stderr, "could not obtain winbind interface " - "details!\n"); + "details: %s\n", wbcErrorString(wbc_status)); } return details; @@ -172,6 +173,8 @@ static bool wbinfo_get_userinfo(char *user) wbc_status = wbcGetpwnam(user, &pwd); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcGetpwnam: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -184,6 +187,8 @@ static bool wbinfo_get_userinfo(char *user) pwd->pw_dir, pwd->pw_shell); + wbcFreeMemory(pwd); + return true; } @@ -195,6 +200,8 @@ static bool wbinfo_get_uidinfo(int uid) wbc_status = wbcGetpwuid(uid, &pwd); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcGetpwuid: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -207,6 +214,8 @@ static bool wbinfo_get_uidinfo(int uid) pwd->pw_dir, pwd->pw_shell); + wbcFreeMemory(pwd); + return true; } @@ -219,6 +228,8 @@ static bool wbinfo_get_user_sidinfo(const char *sid_str) wbc_status = wbcStringToSid(sid_str, &sid); wbc_status = wbcGetpwsid(&sid, &pwd); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcGetpwsid: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -244,6 +255,8 @@ static bool wbinfo_get_groupinfo(const char *group) wbc_status = wbcGetgrnam(group, &grp); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcGetgrnam: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -273,6 +286,8 @@ static bool wbinfo_get_gidinfo(int gid) wbc_status = wbcGetgrgid(gid, &grp); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcGetgrgid: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -306,6 +321,8 @@ static bool wbinfo_get_usergroups(const char *user) wbc_status = wbcGetGroups(user, &num_groups, &groups); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcGetGroups: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -331,23 +348,22 @@ static bool wbinfo_get_usersids(const char *user_sid_str) wbc_status = wbcStringToSid(user_sid_str, &user_sid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcStringToSid: %s\n", + wbcErrorString(wbc_status)); return false; } wbc_status = wbcLookupUserSids(&user_sid, false, &num_sids, &sids); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcLookupUserSids: %s\n", + wbcErrorString(wbc_status)); return false; } for (i = 0; i < num_sids; i++) { - char *str = NULL; - wbc_status = wbcSidToString(&sids[i], &str); - if (!WBC_ERROR_IS_OK(wbc_status)) { - wbcFreeMemory(sids); - return false; - } + char str[WBC_SID_STRING_BUFLEN]; + wbcSidToStringBuf(&sids[i], str, sizeof(str)); d_printf("%s\n", str); - wbcFreeMemory(str); } wbcFreeMemory(sids); @@ -366,23 +382,22 @@ static bool wbinfo_get_userdomgroups(const char *user_sid_str) wbc_status = wbcStringToSid(user_sid_str, &user_sid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcStringToSid: %s\n", + wbcErrorString(wbc_status)); return false; } wbc_status = wbcLookupUserSids(&user_sid, true, &num_sids, &sids); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcLookupUserSids: %s\n", + wbcErrorString(wbc_status)); return false; } for (i = 0; i < num_sids; i++) { - char *str = NULL; - wbc_status = wbcSidToString(&sids[i], &str); - if (!WBC_ERROR_IS_OK(wbc_status)) { - wbcFreeMemory(sids); - return false; - } + char str[WBC_SID_STRING_BUFLEN]; + wbcSidToStringBuf(&sids[i], str, sizeof(str)); d_printf("%s\n", str); - wbcFreeMemory(str); } wbcFreeMemory(sids); @@ -399,7 +414,7 @@ static bool wbinfo_get_sidaliases(const char *domain, struct wbcDomainSid user_sid; uint32_t *alias_rids = NULL; uint32_t num_alias_rids; - char *domain_sid_str = NULL; + char domain_sid_str[WBC_SID_STRING_BUFLEN]; /* Send request */ if ((domain == NULL) || (strequal(domain, ".")) || @@ -411,8 +426,8 @@ static bool wbinfo_get_sidaliases(const char *domain, wbc_status = wbcDomainInfo(domain, &dinfo); if (!WBC_ERROR_IS_OK(wbc_status)) { - d_printf("wbcDomainInfo(%s) failed: %s\n", domain, - wbcErrorString(wbc_status)); + d_fprintf(stderr, "wbcDomainInfo(%s) failed: %s\n", domain, + wbcErrorString(wbc_status)); goto done; } wbc_status = wbcStringToSid(user_sid_str, &user_sid); @@ -426,10 +441,7 @@ static bool wbinfo_get_sidaliases(const char *domain, goto done; } - wbc_status = wbcSidToString(&dinfo->sid, &domain_sid_str); - if (!WBC_ERROR_IS_OK(wbc_status)) { - goto done; - } + wbcSidToStringBuf(&dinfo->sid, domain_sid_str, sizeof(domain_sid_str)); for (i = 0; i < num_alias_rids; i++) { d_printf("%s-%d\n", domain_sid_str, alias_rids[i]); @@ -438,12 +450,7 @@ static bool wbinfo_get_sidaliases(const char *domain, wbcFreeMemory(alias_rids); done: - if (domain_sid_str) { - wbcFreeMemory(domain_sid_str); - } - if (dinfo) { - wbcFreeMemory(dinfo); - } + wbcFreeMemory(dinfo); return (WBC_ERR_SUCCESS == wbc_status); } @@ -457,6 +464,8 @@ static bool wbinfo_wins_byname(const char *name) wbc_status = wbcResolveWinsByName(name, &ip); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcResolveWinsByName: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -478,6 +487,8 @@ static bool wbinfo_wins_byip(const char *ip) wbc_status = wbcResolveWinsByIP(ip, &name); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcResolveWinsByIP: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -502,6 +513,8 @@ static bool wbinfo_list_domains(bool list_all_domains, bool verbose) wbc_status = wbcListTrusts(&domain_list, &num_domains); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcListTrusts: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -558,6 +571,8 @@ static bool wbinfo_list_domains(bool list_all_domains, bool verbose) d_printf("\n"); } + wbcFreeMemory(domain_list); + return true; } @@ -588,6 +603,8 @@ static bool wbinfo_show_onlinestatus(const char *domain) wbc_status = wbcListTrusts(&domain_list, &num_domains); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcListTrusts: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -608,6 +625,8 @@ static bool wbinfo_show_onlinestatus(const char *domain) is_offline ? "offline" : "online" ); } + wbcFreeMemory(domain_list); + return true; } @@ -618,7 +637,7 @@ static bool wbinfo_domain_info(const char *domain) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct wbcDomainInfo *dinfo = NULL; - char *sid_str = NULL; + char sid_str[WBC_SID_STRING_BUFLEN]; if ((domain == NULL) || (strequal(domain, ".")) || (domain[0] == '\0')){ domain = get_winbind_domain(); @@ -628,14 +647,12 @@ static bool wbinfo_domain_info(const char *domain) wbc_status = wbcDomainInfo(domain, &dinfo); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcDomainInfo: %s\n", + wbcErrorString(wbc_status)); return false; } - wbc_status = wbcSidToString(&dinfo->sid, &sid_str); - if (!WBC_ERROR_IS_OK(wbc_status)) { - wbcFreeMemory(dinfo); - return false; - } + wbcSidToStringBuf(&dinfo->sid, sid_str, sizeof(sid_str)); /* Display response */ @@ -654,7 +671,6 @@ static bool wbinfo_domain_info(const char *domain) (dinfo->domain_flags & WBC_DOMINFO_DOMAIN_PRIMARY) ? "Yes" : "No"); - wbcFreeMemory(sid_str); wbcFreeMemory(dinfo); return true; @@ -742,12 +758,39 @@ static bool wbinfo_check_secret(const char *domain) wbcFreeMemory(error); } if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcCheckTrustCredentials: " + "%s\n", wbcErrorString(wbc_status)); return false; } return true; } +/* Find the currently connected DCs */ + +static bool wbinfo_dc_info(const char *domain_name) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + size_t i, num_dcs; + const char **dc_names, **dc_ips; + + wbc_status = wbcDcInfo(domain_name, &num_dcs, + &dc_names, &dc_ips); + if (!WBC_ERROR_IS_OK(wbc_status)) { + printf("Could not find dc info %s\n", + domain_name ? domain_name : "our domain"); + return false; + } + + for (i=0; i<num_dcs; i++) { + printf("%s (%s)\n", dc_names[i], dc_ips[i]); + } + wbcFreeMemory(dc_names); + wbcFreeMemory(dc_ips); + + return true; +} + /* Change trust account password */ static bool wbinfo_change_secret(const char *domain) @@ -774,6 +817,8 @@ static bool wbinfo_change_secret(const char *domain) wbcFreeMemory(error); } if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcChangeTrustCredentials: " + "%s\n", wbcErrorString(wbc_status)); return false; } @@ -798,6 +843,8 @@ static bool wbinfo_ping_dc(void) wbcFreeMemory(error); } if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcPingDc: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -810,26 +857,23 @@ static bool wbinfo_uid_to_sid(uid_t uid) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct wbcDomainSid sid; - char *sid_str = NULL; + char sid_str[WBC_SID_STRING_BUFLEN]; /* Send request */ wbc_status = wbcUidToSid(uid, &sid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcUidToSid: %s\n", + wbcErrorString(wbc_status)); return false; } - wbc_status = wbcSidToString(&sid, &sid_str); - if (!WBC_ERROR_IS_OK(wbc_status)) { - return false; - } + wbcSidToStringBuf(&sid, sid_str, sizeof(sid_str)); /* Display response */ d_printf("%s\n", sid_str); - wbcFreeMemory(sid_str); - return true; } @@ -839,26 +883,23 @@ static bool wbinfo_gid_to_sid(gid_t gid) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct wbcDomainSid sid; - char *sid_str = NULL; + char sid_str[WBC_SID_STRING_BUFLEN]; /* Send request */ wbc_status = wbcGidToSid(gid, &sid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcGidToSid: %s\n", + wbcErrorString(wbc_status)); return false; } - wbc_status = wbcSidToString(&sid, &sid_str); - if (!WBC_ERROR_IS_OK(wbc_status)) { - return false; - } + wbcSidToStringBuf(&sid, sid_str, sizeof(sid_str)); /* Display response */ d_printf("%s\n", sid_str); - wbcFreeMemory(sid_str); - return true; } @@ -874,11 +915,15 @@ static bool wbinfo_sid_to_uid(const char *sid_str) wbc_status = wbcStringToSid(sid_str, &sid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcStringToSid: %s\n", + wbcErrorString(wbc_status)); return false; } wbc_status = wbcSidToUid(&sid, &uid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcSidToUid: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -899,11 +944,15 @@ static bool wbinfo_sid_to_gid(const char *sid_str) wbc_status = wbcStringToSid(sid_str, &sid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcStringToSid: %s\n", + wbcErrorString(wbc_status)); return false; } wbc_status = wbcSidToGid(&sid, &gid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcSidToGid: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -914,6 +963,74 @@ static bool wbinfo_sid_to_gid(const char *sid_str) return true; } +static bool wbinfo_sids_to_unix_ids(const char *arg) +{ + char sidstr[WBC_SID_STRING_BUFLEN]; + struct wbcDomainSid *sids; + struct wbcUnixId *unix_ids; + int i, num_sids; + const char *p; + wbcErr wbc_status; + + + num_sids = 0; + sids = NULL; + p = arg; + + while (next_token(&p, sidstr, LIST_SEP, sizeof(sidstr))) { + sids = talloc_realloc(talloc_tos(), sids, struct wbcDomainSid, + num_sids+1); + if (sids == NULL) { + d_fprintf(stderr, "talloc failed\n"); + return false; + } + wbc_status = wbcStringToSid(sidstr, &sids[num_sids]); + if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "wbcSidToString(%s) failed: %s\n", + sidstr, wbcErrorString(wbc_status)); + TALLOC_FREE(sids); + return false; + } + num_sids += 1; + } + + unix_ids = talloc_array(talloc_tos(), struct wbcUnixId, num_sids); + if (unix_ids == NULL) { + TALLOC_FREE(sids); + return false; + } + + wbc_status = wbcSidsToUnixIds(sids, num_sids, unix_ids); + if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "wbcSidsToUnixIds failed: %s\n", + wbcErrorString(wbc_status)); + TALLOC_FREE(sids); + return false; + } + + for (i=0; i<num_sids; i++) { + + wbcSidToStringBuf(&sids[i], sidstr, sizeof(sidstr)); + + switch(unix_ids[i].type) { + case WBC_ID_TYPE_UID: + d_printf("%s -> uid %d\n", sidstr, unix_ids[i].id.uid); + break; + case WBC_ID_TYPE_GID: + d_printf("%s -> gid %d\n", sidstr, unix_ids[i].id.gid); + break; + default: + d_printf("%s -> unmapped\n", sidstr); + break; + } + } + + TALLOC_FREE(sids); + TALLOC_FREE(unix_ids); + + return true; +} + static bool wbinfo_allocate_uid(void) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; @@ -923,6 +1040,8 @@ static bool wbinfo_allocate_uid(void) wbc_status = wbcAllocateUid(&uid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcAllocateUid: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -942,6 +1061,8 @@ static bool wbinfo_allocate_gid(void) wbc_status = wbcAllocateGid(&gid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcAllocateGid: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -961,11 +1082,15 @@ static bool wbinfo_set_uid_mapping(uid_t uid, const char *sid_str) wbc_status = wbcStringToSid(sid_str, &sid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcStringToSid: %s\n", + wbcErrorString(wbc_status)); return false; } wbc_status = wbcSetUidMapping(uid, &sid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcSetUidMapping: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -986,11 +1111,15 @@ static bool wbinfo_set_gid_mapping(gid_t gid, const char *sid_str) wbc_status = wbcStringToSid(sid_str, &sid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcStringToSid: %s\n", + wbcErrorString(wbc_status)); return false; } wbc_status = wbcSetGidMapping(gid, &sid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcSetGidMapping: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -1011,11 +1140,15 @@ static bool wbinfo_remove_uid_mapping(uid_t uid, const char *sid_str) wbc_status = wbcStringToSid(sid_str, &sid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcStringToSid: %s\n", + wbcErrorString(wbc_status)); return false; } wbc_status = wbcRemoveUidMapping(uid, &sid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcRemoveUidMapping: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -1036,11 +1169,15 @@ static bool wbinfo_remove_gid_mapping(gid_t gid, const char *sid_str) wbc_status = wbcStringToSid(sid_str, &sid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcStringToSid: %s\n", + wbcErrorString(wbc_status)); return false; } wbc_status = wbcRemoveGidMapping(gid, &sid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcRemoveGidMapping: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -1066,11 +1203,15 @@ static bool wbinfo_lookupsid(const char *sid_str) wbc_status = wbcStringToSid(sid_str, &sid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcStringToSid: %s\n", + wbcErrorString(wbc_status)); return false; } wbc_status = wbcLookupSid(&sid, &domain, &name, &type); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcLookupSid: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -1096,11 +1237,15 @@ static bool wbinfo_lookupsid_fullname(const char *sid_str) wbc_status = wbcStringToSid(sid_str, &sid); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcStringToSid: %s\n", + wbcErrorString(wbc_status)); return false; } wbc_status = wbcGetDisplayName(&sid, &domain, &name, &type); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcGetDisplayName: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -1184,20 +1329,64 @@ static bool wbinfo_lookuprids(const char *domain, const char *arg) ret = true; done: - if (dinfo) { - wbcFreeMemory(dinfo); - } - if (domain_name) { - wbcFreeMemory(domain_name); + wbcFreeMemory(dinfo); + wbcFreeMemory(domain_name); + wbcFreeMemory(names); + wbcFreeMemory(types); + TALLOC_FREE(mem_ctx); + return ret; +} + +static bool wbinfo_lookup_sids(const char *arg) +{ + char sidstr[WBC_SID_STRING_BUFLEN]; + struct wbcDomainSid *sids; + struct wbcDomainInfo *domains; + struct wbcTranslatedName *names; + int num_domains; + int i, num_sids; + const char *p; + wbcErr wbc_status; + + + num_sids = 0; + sids = NULL; + p = arg; + + while (next_token(&p, sidstr, LIST_SEP, sizeof(sidstr))) { + sids = talloc_realloc(talloc_tos(), sids, struct wbcDomainSid, + num_sids+1); + if (sids == NULL) { + d_fprintf(stderr, "talloc failed\n"); + return false; + } + wbc_status = wbcStringToSid(sidstr, &sids[num_sids]); + if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "wbcSidToString(%s) failed: %s\n", + sidstr, wbcErrorString(wbc_status)); + TALLOC_FREE(sids); + return false; + } + num_sids += 1; } - if (names) { - wbcFreeMemory(names); + + wbc_status = wbcLookupSids(sids, num_sids, &domains, &num_domains, + &names); + if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "wbcLookupSids failed: %s\n", + wbcErrorString(wbc_status)); + TALLOC_FREE(sids); + return false; } - if (types) { - wbcFreeMemory(types); + + for (i=0; i<num_sids; i++) { + wbcSidToStringBuf(&sids[i], sidstr, sizeof(sidstr)); + + d_printf("%s -> %s\\%s %d\n", sidstr, + domains[names[i].domain_index].short_name, + names[i].name, names[i].type); } - TALLOC_FREE(mem_ctx); - return ret; + return true; } /* Convert string to sid */ @@ -1206,7 +1395,7 @@ static bool wbinfo_lookupname(const char *full_name) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct wbcDomainSid sid; - char *sid_str; + char sid_str[WBC_SID_STRING_BUFLEN]; enum wbcSidType type; fstring domain_name; fstring account_name; @@ -1219,20 +1408,17 @@ static bool wbinfo_lookupname(const char *full_name) wbc_status = wbcLookupName(domain_name, account_name, &sid, &type); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcLookupName: %s\n", + wbcErrorString(wbc_status)); return false; } - wbc_status = wbcSidToString(&sid, &sid_str); - if (!WBC_ERROR_IS_OK(wbc_status)) { - return false; - } + wbcSidToStringBuf(&sid, sid_str, sizeof(sid_str)); /* Display response */ d_printf("%s %s (%d)\n", sid_str, wbcSidTypeString(type), type); - wbcFreeMemory(sid_str); - return true; } @@ -1311,6 +1497,8 @@ static bool wbinfo_auth_krb5(char *username, const char *cctype, uint32_t flags) (uint8_t *)&flags, sizeof(flags)); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcAddNamedBlob: %s\n", + wbcErrorString(wbc_status)); goto done; } @@ -1321,6 +1509,8 @@ static bool wbinfo_auth_krb5(char *username, const char *cctype, uint32_t flags) (uint8_t *)&uid, sizeof(uid)); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcAddNamedBlob: %s\n", + wbcErrorString(wbc_status)); goto done; } @@ -1331,6 +1521,8 @@ static bool wbinfo_auth_krb5(char *username, const char *cctype, uint32_t flags) (uint8_t *)local_cctype, strlen(cctype)+1); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcAddNamedBlob: %s\n", + wbcErrorString(wbc_status)); goto done; } @@ -1343,7 +1535,7 @@ static bool wbinfo_auth_krb5(char *username, const char *cctype, uint32_t flags) if (error) { d_fprintf(stderr, - "error code was %s (0x%x)\nerror messsage was: %s\n", + "error code was %s (0x%x)\nerror message was: %s\n", error->nt_string, error->nt_status, error->display_string); @@ -1414,7 +1606,7 @@ static bool wbinfo_auth(char *username) #if 0 if (response.data.auth.nt_status) d_fprintf(stderr, - "error code was %s (0x%x)\nerror messsage was: %s\n", + "error code was %s (0x%x)\nerror message was: %s\n", response.data.auth.nt_status_string, response.data.auth.nt_status, response.data.auth.error_string); @@ -1515,7 +1707,7 @@ static bool wbinfo_auth_crap(char *username, bool use_ntlmv2, bool use_lanman) if (wbc_status == WBC_ERR_AUTH_ERROR) { d_fprintf(stderr, - "error code was %s (0x%x)\nerror messsage was: %s\n", + "error code was %s (0x%x)\nerror message was: %s\n", err->nt_string, err->nt_status, err->display_string); @@ -1530,6 +1722,75 @@ static bool wbinfo_auth_crap(char *username, bool use_ntlmv2, bool use_lanman) return WBC_ERROR_IS_OK(wbc_status); } +/* Authenticate a user with a plaintext password */ + +static bool wbinfo_pam_logon(char *username) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + struct wbcLogonUserParams params; + struct wbcAuthErrorInfo *error; + char *s = NULL; + char *p = NULL; + TALLOC_CTX *frame = talloc_tos(); + uint32_t flags; + uint32_t uid; + + ZERO_STRUCT(params); + + if ((s = talloc_strdup(frame, username)) == NULL) { + return false; + } + + if ((p = strchr(s, '%')) != NULL) { + *p = 0; + p++; + params.password = talloc_strdup(frame, p); + } else { + params.password = wbinfo_prompt_pass(frame, NULL, username); + } + params.username = s; + + flags = WBFLAG_PAM_CACHED_LOGIN; + + wbc_status = wbcAddNamedBlob(¶ms.num_blobs, ¶ms.blobs, + "flags", 0, + (uint8_t *)&flags, sizeof(flags)); + if (!WBC_ERROR_IS_OK(wbc_status)) { + d_printf("wbcAddNamedBlob failed: %s\n", + wbcErrorString(wbc_status)); + return false; + } + + uid = getuid(); + + wbc_status = wbcAddNamedBlob(¶ms.num_blobs, ¶ms.blobs, + "user_uid", 0, + (uint8_t *)&uid, sizeof(uid)); + if (!WBC_ERROR_IS_OK(wbc_status)) { + d_printf("wbcAddNamedBlob failed: %s\n", + wbcErrorString(wbc_status)); + return false; + } + + wbc_status = wbcLogonUser(¶ms, NULL, &error, NULL); + + wbcFreeMemory(params.blobs); + + d_printf("plaintext password authentication %s\n", + WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed"); + + if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, + "error code was %s (0x%x)\nerror message was: %s\n", + error->nt_string, + (int)error->nt_status, + error->display_string); + wbcFreeMemory(error); + return false; + } + return true; +} + /* Save creds with winbind */ static bool wbinfo_ccache_save(char *username) @@ -1606,7 +1867,7 @@ static bool wbinfo_klog(char *username) if (response.data.auth.nt_status) d_fprintf(stderr, - "error code was %s (0x%x)\nerror messsage was: %s\n", + "error code was %s (0x%x)\nerror message was: %s\n", response.data.auth.nt_status_string, response.data.auth.nt_status, response.data.auth.error_string); @@ -1683,6 +1944,8 @@ static bool print_domain_groups(const char *domain) wbc_status = wbcListGroups(domain, &num_groups, &groups); if (!WBC_ERROR_IS_OK(wbc_status)) { + d_fprintf(stderr, "failed to call wbcListGroups: %s\n", + wbcErrorString(wbc_status)); return false; } @@ -1753,15 +2016,18 @@ enum { OPT_SEQUENCE, OPT_GETDCNAME, OPT_DSGETDCNAME, + OPT_DC_INFO, OPT_USERDOMGROUPS, OPT_SIDALIASES, OPT_USERSIDS, + OPT_LOOKUP_SIDS, OPT_ALLOCATE_UID, OPT_ALLOCATE_GID, OPT_SET_UID_MAPPING, OPT_SET_GID_MAPPING, OPT_REMOVE_UID_MAPPING, OPT_REMOVE_GID_MAPPING, + OPT_SIDS_TO_XIDS, OPT_SEPARATOR, OPT_LIST_ALL_DOMAINS, OPT_LIST_OWN_DOMAIN, @@ -1772,10 +2038,13 @@ enum { OPT_VERBOSE, OPT_ONLINESTATUS, OPT_CHANGE_USER_PASSWORD, - OPT_PING_DC, OPT_CCACHE_SAVE, OPT_SID_TO_FULLNAME, OPT_NTLMV2, + OPT_PAM_LOGON, + OPT_LOGOFF, + OPT_LOGOFF_USER, + OPT_LOGOFF_UID, OPT_LANMAN }; @@ -1793,6 +2062,8 @@ int main(int argc, char **argv, char **envp) bool verbose = false; bool use_ntlmv2 = false; bool use_lanman = false; + char *logoff_user = getenv("USER"); + int logoff_uid = geteuid(); struct poptOption long_options[] = { POPT_AUTOHELP @@ -1809,6 +2080,9 @@ int main(int argc, char **argv, char **envp) { "sid-to-fullname", 0, POPT_ARG_STRING, &string_arg, OPT_SID_TO_FULLNAME, "Converts sid to fullname", "SID" }, { "lookup-rids", 'R', POPT_ARG_STRING, &string_arg, 'R', "Converts RIDs to names", "RIDs" }, + { "lookup-sids", 0, POPT_ARG_STRING, &string_arg, + OPT_LOOKUP_SIDS, "Converts SIDs to types and names", + "Sid-List"}, { "uid-to-sid", 'U', POPT_ARG_INT, &int_arg, 'U', "Converts uid to sid" , "UID" }, { "gid-to-sid", 'G', POPT_ARG_INT, &int_arg, 'G', "Converts gid to sid", "GID" }, { "sid-to-uid", 'S', POPT_ARG_STRING, &string_arg, 'S', "Converts sid to uid", "SID" }, @@ -1821,14 +2095,16 @@ int main(int argc, char **argv, char **envp) { "set-gid-mapping", 0, POPT_ARG_STRING, &string_arg, OPT_SET_GID_MAPPING, "Create or modify gid to sid mapping in idmap", "GID,SID" }, { "remove-uid-mapping", 0, POPT_ARG_STRING, &string_arg, OPT_REMOVE_UID_MAPPING, "Remove uid to sid mapping in idmap", "UID,SID" }, { "remove-gid-mapping", 0, POPT_ARG_STRING, &string_arg, OPT_REMOVE_GID_MAPPING, "Remove gid to sid mapping in idmap", "GID,SID" }, + { "sids-to-unix-ids", 0, POPT_ARG_STRING, &string_arg, + OPT_SIDS_TO_XIDS, "Translate SIDs to Unix IDs", "Sid-List" }, { "check-secret", 't', POPT_ARG_NONE, 0, 't', "Check shared secret" }, { "change-secret", 'c', POPT_ARG_NONE, 0, 'c', "Change shared secret" }, - { "ping-dc", 0, POPT_ARG_NONE, 0, OPT_PING_DC, + { "ping-dc", 'P', POPT_ARG_NONE, 0, 'P', "Check the NETLOGON connection" }, { "trusted-domains", 'm', POPT_ARG_NONE, 0, 'm', "List trusted domains" }, { "all-domains", 0, POPT_ARG_NONE, 0, OPT_LIST_ALL_DOMAINS, "List all domains (trusted and own domain)" }, { "own-domain", 0, POPT_ARG_NONE, 0, OPT_LIST_OWN_DOMAIN, "List own domain" }, - { "sequence", 0, POPT_ARG_NONE, 0, OPT_SEQUENCE, "Show sequence numbers of all domains" }, + { "sequence", 0, POPT_ARG_NONE, 0, OPT_SEQUENCE, "Deprecated command, see --online-status" }, { "online-status", 0, POPT_ARG_NONE, 0, OPT_ONLINESTATUS, "Show whether domains are marked as online or offline"}, { "domain-info", 'D', POPT_ARG_STRING, &string_arg, 'D', "Show most of the info we have about the domain" }, { "user-info", 'i', POPT_ARG_STRING, &string_arg, 'i', "Get user info", "USER" }, @@ -1842,6 +2118,14 @@ int main(int argc, char **argv, char **envp) { "sid-aliases", 0, POPT_ARG_STRING, &string_arg, OPT_SIDALIASES, "Get sid aliases", "SID" }, { "user-sids", 0, POPT_ARG_STRING, &string_arg, OPT_USERSIDS, "Get user group sids for user SID", "SID" }, { "authenticate", 'a', POPT_ARG_STRING, &string_arg, 'a', "authenticate user", "user%password" }, + { "pam-logon", 0, POPT_ARG_STRING, &string_arg, OPT_PAM_LOGON, + "do a pam logon equivalent", "user%password" }, + { "logoff", 0, POPT_ARG_NONE, NULL, OPT_LOGOFF, + "log off user", "uid" }, + { "logoff-user", 0, POPT_ARG_STRING, &logoff_user, + OPT_LOGOFF_USER, "username to log off" }, + { "logoff-uid", 0, POPT_ARG_INT, &logoff_uid, + OPT_LOGOFF_UID, "uid to log off" }, { "set-auth-user", 0, POPT_ARG_STRING, &string_arg, OPT_SET_AUTH_USER, "Store user and password used by winbindd (root only)", "user%password" }, { "ccache-save", 0, POPT_ARG_STRING, &string_arg, OPT_CCACHE_SAVE, "Store user and password for ccache " @@ -1849,6 +2133,8 @@ int main(int argc, char **argv, char **envp) { "getdcname", 0, POPT_ARG_STRING, &string_arg, OPT_GETDCNAME, "Get a DC name for a foreign domain", "domainname" }, { "dsgetdcname", 0, POPT_ARG_STRING, &string_arg, OPT_DSGETDCNAME, "Find a DC for a domain", "domainname" }, + { "dc-info", 0, POPT_ARG_STRING, &string_arg, OPT_DC_INFO, + "Find the currently known DCs", "domainname" }, { "get-auth-user", 0, POPT_ARG_NONE, NULL, OPT_GET_AUTH_USER, "Retrieve user and password used by winbindd (root only)", NULL }, { "ping", 'p', POPT_ARG_NONE, 0, 'p', "Ping winbindd to see if it is alive" }, { "domain", 0, POPT_ARG_STRING, &opt_domain_name, OPT_DOMAIN_NAME, "Define to the domain to restrict operation", "domain" }, @@ -1943,6 +2229,13 @@ int main(int argc, char **argv, char **envp) goto done; } break; + case OPT_LOOKUP_SIDS: + if (!wbinfo_lookup_sids(string_arg)) { + d_fprintf(stderr, "Could not lookup SIDs %s\n", + string_arg); + goto done; + } + break; case 'n': if (!wbinfo_lookupname(string_arg)) { d_fprintf(stderr, "Could not lookup name %s\n", @@ -2052,6 +2345,13 @@ int main(int argc, char **argv, char **envp) goto done; } break; + case OPT_SIDS_TO_XIDS: + if (!wbinfo_sids_to_unix_ids(string_arg)) { + d_fprintf(stderr, "wbinfo_sids_to_unix_ids " + "failed\n"); + goto done; + } + break; case 't': if (!wbinfo_check_secret(opt_domain_name)) { d_fprintf(stderr, "Could not check secret\n"); @@ -2064,7 +2364,7 @@ int main(int argc, char **argv, char **envp) goto done; } break; - case OPT_PING_DC: + case 'P': if (!wbinfo_ping_dc()) { d_fprintf(stderr, "Could not ping our DC\n"); goto done; @@ -2191,6 +2491,23 @@ int main(int argc, char **argv, char **envp) goto done; break; } + case OPT_PAM_LOGON: + if (!wbinfo_pam_logon(string_arg)) { + d_fprintf(stderr, "pam_logon failed for %s\n", + string_arg); + goto done; + } + break; + case OPT_LOGOFF: + { + wbcErr wbc_status; + + wbc_status = wbcLogoffUser(logoff_user, logoff_uid, + ""); + d_printf("Logoff %s (%d): %s\n", logoff_user, + logoff_uid, wbcErrorString(wbc_status)); + break; + } case 'K': { uint32_t flags = WBFLAG_PAM_KRB5 | WBFLAG_PAM_CACHED_LOGIN | @@ -2245,6 +2562,11 @@ int main(int argc, char **argv, char **envp) goto done; } break; + case OPT_DC_INFO: + if (!wbinfo_dc_info(string_arg)) { + goto done; + } + break; case OPT_SEPARATOR: { const char sep = winbind_separator(); if ( !sep ) { @@ -2274,12 +2596,11 @@ int main(int argc, char **argv, char **envp) /* generic configuration options */ case OPT_DOMAIN_NAME: - break; case OPT_VERBOSE: - break; case OPT_NTLMV2: - break; case OPT_LANMAN: + case OPT_LOGOFF_USER: + case OPT_LOGOFF_UID: break; default: d_fprintf(stderr, "Invalid option\n"); diff --git a/nsswitch/winbind_client.h b/nsswitch/winbind_client.h index b004d9c2c0..905a189c82 100644 --- a/nsswitch/winbind_client.h +++ b/nsswitch/winbind_client.h @@ -1,7 +1,33 @@ +/* + Unix SMB/CIFS implementation. + + winbind client common code + + Copyright (C) Tim Potter 2000 + Copyright (C) Andrew Tridgell 2000 + Copyright (C) Andrew Bartlett 2002 + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _NSSWITCH_WINBIND_CLIENT_H_ +#define _NSSWITCH_WINBIND_CLIENT_H_ + #include "winbind_nss_config.h" #include "winbind_struct_protocol.h" -void winbindd_init_request(struct winbindd_request *req,int rq_type); void winbindd_free_response(struct winbindd_response *response); NSS_STATUS winbindd_send_request(int req_type, int need_priv, struct winbindd_request *request); @@ -12,8 +38,6 @@ NSS_STATUS winbindd_request_response(int req_type, NSS_STATUS winbindd_priv_request_response(int req_type, struct winbindd_request *request, struct winbindd_response *response); -int winbindd_read_reply(struct winbindd_response *response); - #define winbind_env_set() \ (strcmp(getenv(WINBINDD_DONT_ENV)?getenv(WINBINDD_DONT_ENV):"0","1") == 0) @@ -23,8 +47,4 @@ int winbindd_read_reply(struct winbindd_response *response); #define winbind_on() \ (setenv(WINBINDD_DONT_ENV, "0", 1) == 0) -int winbind_write_sock(void *buffer, int count, int recursing, int need_priv); -int winbind_read_sock(void *buffer, int count); -void winbind_close_sock(void); - -const char *nss_err_str(NSS_STATUS ret); +#endif /* _NSSWITCH_WINBIND_CLIENT_H_ */ diff --git a/nsswitch/winbind_nss_hpux.h b/nsswitch/winbind_nss_hpux.h index 40a352d4d3..dba70a7657 100644 --- a/nsswitch/winbind_nss_hpux.h +++ b/nsswitch/winbind_nss_hpux.h @@ -130,7 +130,12 @@ typedef struct nss_XbyY_args { void *returnval; int erange; - int h_errno; + /* + * h_errno is defined as function call macro for multithreaded applications + * in HP-UX. *this* h_errno is not used in the HP-UX codepath of our nss + * modules, so let's simply rename it: + */ + int h_errno_unused; nss_status_t status; } nss_XbyY_args_t; diff --git a/nsswitch/winbind_nss_linux.c b/nsswitch/winbind_nss_linux.c index 4a7943278e..7b16752043 100644 --- a/nsswitch/winbind_nss_linux.c +++ b/nsswitch/winbind_nss_linux.c @@ -71,6 +71,31 @@ NSS_STATUS _nss_winbind_uidtosid(uid_t uid, char **sid, char *buffer, NSS_STATUS _nss_winbind_gidtosid(gid_t gid, char **sid, char *buffer, size_t buflen, int *errnop); +/************************************************************************* + ************************************************************************/ + +#ifdef DEBUG_NSS +static const char *nss_err_str(NSS_STATUS ret) +{ + switch (ret) { + case NSS_STATUS_TRYAGAIN: + return "NSS_STATUS_TRYAGAIN"; + case NSS_STATUS_SUCCESS: + return "NSS_STATUS_SUCCESS"; + case NSS_STATUS_NOTFOUND: + return "NSS_STATUS_NOTFOUND"; + case NSS_STATUS_UNAVAIL: + return "NSS_STATUS_UNAVAIL"; +#ifdef NSS_STATUS_RETURN + case NSS_STATUS_RETURN: + return "NSS_STATUS_RETURN"; +#endif + default: + return "UNKNOWN RETURN CODE!!!!!!!"; + } +} +#endif + /* Prototypes from wb_common.c */ /* Allocate some space from the nss static buffer. The buffer and buflen diff --git a/nsswitch/winbind_nss_solaris.h b/nsswitch/winbind_nss_solaris.h index f805542f75..011330576d 100644 --- a/nsswitch/winbind_nss_solaris.h +++ b/nsswitch/winbind_nss_solaris.h @@ -22,33 +22,7 @@ #ifndef _WINBIND_NSS_SOLARIS_H #define _WINBIND_NSS_SOLARIS_H -/* Solaris has a broken nss_common header file containing C++ reserved names. */ -#ifndef __cplusplus -#undef class -#undef private -#undef public -#undef protected -#undef template -#undef this -#undef new -#undef delete -#undef friend -#endif - #include <nss_common.h> - -#ifndef __cplusplus -#define class #error DONT_USE_CPLUSPLUS_RESERVED_NAMES -#define private #error DONT_USE_CPLUSPLUS_RESERVED_NAMES -#define public #error DONT_USE_CPLUSPLUS_RESERVED_NAMES -#define protected #error DONT_USE_CPLUSPLUS_RESERVED_NAMES -#define template #error DONT_USE_CPLUSPLUS_RESERVED_NAMES -#define this #error DONT_USE_CPLUSPLUS_RESERVED_NAMES -#define new #error DONT_USE_CPLUSPLUS_RESERVED_NAMES -#define delete #error DONT_USE_CPLUSPLUS_RESERVED_NAMES -#define friend #error DONT_USE_CPLUSPLUS_RESERVED_NAMES -#endif - #include <nss_dbdefs.h> #include <nsswitch.h> diff --git a/nsswitch/winbind_struct_protocol.h b/nsswitch/winbind_struct_protocol.h index 2e0751f79a..e5ed8e1b3a 100644 --- a/nsswitch/winbind_struct_protocol.h +++ b/nsswitch/winbind_struct_protocol.h @@ -50,12 +50,18 @@ typedef char fstring[FSTRING_LEN]; * 22: added WINBINDD_PING_DC * 23: added session_key to ccache_ntlm_auth response * added WINBINDD_CCACHE_SAVE + * 24: Fill in num_entries WINBINDD_LIST_USERS and WINBINDD_LIST_GROUPS + * 25: removed WINBINDD_SET_HWM + * removed WINBINDD_SET_MAPPING + * removed WINBINDD_REMOVE_MAPPING + * 26: added WINBINDD_DC_INFO + * 27: added WINBINDD_LOOKUPSIDS */ -#define WINBIND_INTERFACE_VERSION 23 +#define WINBIND_INTERFACE_VERSION 27 /* Have to deal with time_t being 4 or 8 bytes due to structure alignment. On a 64bit Linux box, we have to support a constant structure size - between /lib/libnss_winbind.so.2 and /li64/libnss_winbind.so.2. + between /lib/libnss_winbind.so.2 and /lib64/libnss_winbind.so.2. The easiest way to do this is to always use 8byte values for time_t. */ #define SMB_TIME_T int64_t @@ -103,6 +109,7 @@ enum winbindd_cmd { WINBINDD_LOOKUPSID, WINBINDD_LOOKUPNAME, WINBINDD_LOOKUPRIDS, + WINBINDD_LOOKUPSIDS, /* Lookup functions */ @@ -114,9 +121,6 @@ enum winbindd_cmd { WINBINDD_ALLOCATE_UID, WINBINDD_ALLOCATE_GID, - WINBINDD_SET_MAPPING, - WINBINDD_REMOVE_MAPPING, - WINBINDD_SET_HWM, /* Miscellaneous other stuff */ @@ -131,6 +135,7 @@ enum winbindd_cmd { struct winbindd_domain */ WINBINDD_GETDCNAME, /* Issue a GetDCName Request */ WINBINDD_DSGETDCNAME, /* Issue a DsGetDCName Request */ + WINBINDD_DC_INFO, /* Which DC are we connected to? */ WINBINDD_SHOW_SEQUENCE, /* display sequence numbers of domains */ @@ -166,9 +171,6 @@ enum winbindd_cmd { WINBINDD_DUAL_SIDS2XIDS, WINBINDD_DUAL_UID2SID, WINBINDD_DUAL_GID2SID, - WINBINDD_DUAL_SET_MAPPING, - WINBINDD_DUAL_REMOVE_MAPPING, - WINBINDD_DUAL_SET_HWM, /* Wrapper around possibly blocking unix nss calls */ WINBINDD_DUAL_USERINFO, diff --git a/nsswitch/wins.c b/nsswitch/wins.c index aa95ec7340..f5fd7a775e 100644 --- a/nsswitch/wins.c +++ b/nsswitch/wins.c @@ -19,6 +19,8 @@ */ #include "includes.h" +#include "nsswitch/winbind_nss.h" + #ifdef HAVE_NS_API_H #include <ns_daemon.h> @@ -38,76 +40,28 @@ static pthread_mutex_t wins_nss_mutex = PTHREAD_MUTEX_INITIALIZER; static int initialised; -extern bool AllowDebugChange; - NSS_STATUS _nss_wins_gethostbyname_r(const char *hostname, struct hostent *he, char *buffer, size_t buflen, int *h_errnop); NSS_STATUS _nss_wins_gethostbyname2_r(const char *name, int af, struct hostent *he, char *buffer, size_t buflen, int *h_errnop); -/* Use our own create socket code so we don't recurse.... */ - -static int wins_lookup_open_socket_in(void) -{ - struct sockaddr_in sock; - int val=1; - int res; - - memset((char *)&sock,'\0',sizeof(sock)); - -#ifdef HAVE_SOCK_SIN_LEN - sock.sin_len = sizeof(sock); -#endif - sock.sin_port = 0; - sock.sin_family = AF_INET; - sock.sin_addr.s_addr = interpret_addr("0.0.0.0"); - res = socket(AF_INET, SOCK_DGRAM, 0); - if (res == -1) - return -1; - - if (setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val)) != 0) { - close(res); - return -1; - } -#ifdef SO_REUSEPORT - if (setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val)) != 0) { - close(res); - return -1; - } -#endif /* SO_REUSEPORT */ - - /* now we've got a socket - we need to bind it */ - - if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) < 0) { - close(res); - return(-1); - } - - set_socket_options(res,"SO_BROADCAST"); - - return res; -} - - static void nss_wins_init(void) { initialised = 1; - DEBUGLEVEL = 0; - AllowDebugChange = False; + load_case_tables_library(); + lp_set_cmdline("log level", "0"); TimeInit(); setup_logging("nss_wins",False); - load_case_tables(); lp_load(get_dyn_CONFIGFILE(),True,False,False,True); load_interfaces(); } static struct in_addr *lookup_byname_backend(const char *name, int *count) { - int fd = -1; struct ip_service *address = NULL; struct in_addr *ret = NULL; - int j, flags = 0; + int j; if (!initialised) { nss_wins_init(); @@ -126,64 +80,61 @@ static struct in_addr *lookup_byname_backend(const char *name, int *count) free(ret); return NULL; } - *ret = ((struct sockaddr_in *)&address[0].ss)->sin_addr; + *ret = ((struct sockaddr_in *)(void *)&address[0].ss) + ->sin_addr; free( address ); return ret; } - fd = wins_lookup_open_socket_in(); - if (fd == -1) { - return NULL; - } - /* uggh, we have to broadcast to each interface in turn */ for (j=iface_count() - 1;j >= 0;j--) { const struct in_addr *bcast = iface_n_bcast_v4(j); struct sockaddr_storage ss; struct sockaddr_storage *pss; + NTSTATUS status; + if (!bcast) { continue; } in_addr_to_sockaddr_storage(&ss, *bcast); - pss = name_query(fd,name,0x00,True,True,&ss,count, &flags, NULL); - if (pss) { + status = name_query(name, 0x00, True, True, &ss, + NULL, &pss, count, NULL); + if (NT_STATUS_IS_OK(status) && (*count > 0)) { if ((ret = SMB_MALLOC_P(struct in_addr)) == NULL) { return NULL; } *ret = ((struct sockaddr_in *)pss)->sin_addr; + TALLOC_FREE(pss); break; } } - close(fd); return ret; } #ifdef HAVE_NS_API_H -static NODE_STATUS_STRUCT *lookup_byaddr_backend(char *addr, int *count) +static struct node_status *lookup_byaddr_backend(char *addr, int *count) { - int fd; struct sockaddr_storage ss; struct nmb_name nname; - NODE_STATUS_STRUCT *status; + struct node_status *result; + NTSTATUS status; if (!initialised) { nss_wins_init(); } - fd = wins_lookup_open_socket_in(); - if (fd == -1) - return NULL; - make_nmb_name(&nname, "*", 0); if (!interpret_string_addr(&ss, addr, AI_NUMERICHOST)) { return NULL; } - status = node_status_query(fd, &nname, &ss, count, NULL); + status = node_status_query(NULL, &nname, &ss, &result, count, NULL); + if (!NT_STATUS_IS_OK(status)) { + return NULL; + } - close(fd); - return status; + return result; } /* IRIX version */ @@ -201,7 +152,7 @@ int lookup(nsd_file_t *rq) char *key; char *addr; struct in_addr *ip_list; - NODE_STATUS_STRUCT *status; + struct node_status *status; int i, count, len, size; char response[1024]; bool found = False; @@ -233,7 +184,7 @@ int lookup(nsd_file_t *rq) if ( status = lookup_byaddr_backend(key, &count)) { size = strlen(key) + 1; if (size > len) { - free(status); + talloc_free(status); return NSD_ERROR; } len -= size; @@ -245,7 +196,7 @@ int lookup(nsd_file_t *rq) if (status[i].type == 0x20) { size = sizeof(status[i].name) + 1; if (size > len) { - free(status); + talloc_free(status); return NSD_ERROR; } len -= size; @@ -255,7 +206,7 @@ int lookup(nsd_file_t *rq) } } response[strlen(response)-1] = '\n'; - free(status); + talloc_free(status); } } else if (StrCaseCmp(map,"hosts.byname") == 0) { if (ip_list = lookup_byname_backend(key, &count)) { diff --git a/nsswitch/wscript_build b/nsswitch/wscript_build new file mode 100644 index 0000000000..83b10a7969 --- /dev/null +++ b/nsswitch/wscript_build @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +bld.SAMBA_LIBRARY('winbind-client', + source='wb_common.c', + deps='replace', + cflags='-DSOCKET_WRAPPER_DISABLE=1 -DWINBINDD_SOCKET_DIR=\"%s\"' % bld.env.WINBINDD_SOCKET_DIR, + private_library=True + ) + + +bld.SAMBA_BINARY('nsstest', + source='nsstest.c', + deps='replace dl' + ) + + +bld.SAMBA_LIBRARY('nss_winbind', + source='winbind_nss_linux.c', + deps='winbind-client', + realname='libnss_winbind.so.2', + vnum='2') + + +if bld.CONFIG_SET('WITH_PAM_MODULES') or bld.CONFIG_SET('HAVE_PAM_START'): + bld.SAMBA_LIBRARY('pamwinbind', + source='pam_winbind.c', + deps='intl talloc wbclient winbind-client LIBINIPARSER pam', + cflags='-DLOCALEDIR=\"%s/locale\"' % bld.env.DATADIR, + realname='pam_winbind.so', + ) + +if bld.CONFIG_SET('HAVE_KRB5_LOCATE_PLUGIN_H'): + bld.SAMBA_LIBRARY('winbind_krb5_locator', + source='winbind_krb5_locator.c', + deps='wbclient krb5', + realname='winbind_krb5_locator.so') + +bld.SAMBA_SUBSYSTEM('WB_REQTRANS', + source='wb_reqtrans.c', + deps='talloc tevent LIBASYNC_REQ' + ) diff --git a/nsswitch/wscript_configure b/nsswitch/wscript_configure new file mode 100644 index 0000000000..7d6ea82879 --- /dev/null +++ b/nsswitch/wscript_configure @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +conf.CHECK_HEADERS('nss.h nss_common.h ns_api.h') + +conf.CHECK_HEADERS('security/pam_appl.h security/pam_modules.h pam/pam_modules.h', together=True) +conf.CHECK_FUNCS_IN('pam_start', 'pam', checklibc=True, headers='security/pam_appl.h') |