diff options
author | bubulle <bubulle@alioth.debian.org> | 2010-04-04 16:44:16 +0000 |
---|---|---|
committer | bubulle <bubulle@alioth.debian.org> | 2010-04-04 16:44:16 +0000 |
commit | 9e2f5a6ab663f7a111832217c527508c75ddae8a (patch) | |
tree | 2e74616febbb3fb658ce2dcc5f9cff00ad4fdb4a /nsswitch | |
parent | b5556af8f75a4f74db404dd43ee7abafa2be6ca4 (diff) | |
download | samba-9e2f5a6ab663f7a111832217c527508c75ddae8a.tar.gz |
Merge 3.5.1 from experimental
git-svn-id: svn://svn.debian.org/svn/pkg-samba/trunk/samba@3414 fc4039ab-9d04-0410-8cac-899223bdd6b0
Diffstat (limited to 'nsswitch')
-rw-r--r-- | nsswitch/config.mk | 11 | ||||
-rw-r--r-- | nsswitch/libwbclient/config.mk | 15 | ||||
-rw-r--r-- | nsswitch/libwbclient/libwbclient.h | 1 | ||||
-rw-r--r-- | nsswitch/libwbclient/tests/wbclient.c | 326 | ||||
-rw-r--r-- | nsswitch/libwbclient/wb_reqtrans.c | 446 | ||||
-rw-r--r-- | nsswitch/libwbclient/wbc_async.c | 774 | ||||
-rw-r--r-- | nsswitch/libwbclient/wbc_async.h | 95 | ||||
-rw-r--r-- | nsswitch/libwbclient/wbc_guid.c | 1 | ||||
-rw-r--r-- | nsswitch/libwbclient/wbc_idmap.c | 1 | ||||
-rw-r--r-- | nsswitch/libwbclient/wbc_pam.c | 238 | ||||
-rw-r--r-- | nsswitch/libwbclient/wbc_pwd.c | 1 | ||||
-rw-r--r-- | nsswitch/libwbclient/wbc_sid.c | 18 | ||||
-rw-r--r-- | nsswitch/libwbclient/wbc_util.c | 8 | ||||
-rw-r--r-- | nsswitch/libwbclient/wbclient.c | 3 | ||||
-rw-r--r-- | nsswitch/libwbclient/wbclient.h | 50 | ||||
-rw-r--r-- | nsswitch/libwbclient/wbclient_internal.h | 1 | ||||
-rw-r--r-- | nsswitch/nsstest.h | 20 | ||||
-rw-r--r-- | nsswitch/pam_winbind.c | 159 | ||||
-rwxr-xr-x | nsswitch/tests/test_wbinfo.sh | 10 | ||||
-rw-r--r-- | nsswitch/wbinfo.c | 727 | ||||
-rw-r--r-- | nsswitch/wbinfo4.c | 1331 | ||||
-rw-r--r-- | nsswitch/winbind_nss_netbsd.c | 5 | ||||
-rw-r--r-- | nsswitch/winbind_struct_protocol.h | 22 |
23 files changed, 2604 insertions, 1659 deletions
diff --git a/nsswitch/config.mk b/nsswitch/config.mk index 3a4f054d1f..9ad873bed1 100644 --- a/nsswitch/config.mk +++ b/nsswitch/config.mk @@ -2,6 +2,7 @@ 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 @@ -26,9 +27,15 @@ PRIVATE_DEPENDENCIES = \ LIBCLI_AUTH \ LIBPOPT \ POPT_SAMBA \ - LIBWINBIND-CLIENT + LIBWINBIND-CLIENT \ + LIBWBCLIENT \ + LIBTEVENT \ + UTIL_TEVENT \ + LIBASYNC_REQ \ + UID_WRAPPER # End BINARY nsstest ################################# wbinfo_OBJ_FILES = \ - $(nsswitchsrcdir)/wbinfo4.o + $(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 new file mode 100644 index 0000000000..ffdab159f8 --- /dev/null +++ b/nsswitch/libwbclient/config.mk @@ -0,0 +1,15 @@ +[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 74cba7e796..5a25cf462c 100644 --- a/nsswitch/libwbclient/libwbclient.h +++ b/nsswitch/libwbclient/libwbclient.h @@ -36,6 +36,7 @@ /* 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 new file mode 100644 index 0000000000..23fad63025 --- /dev/null +++ b/nsswitch/libwbclient/tests/wbclient.c @@ -0,0 +1,326 @@ +/* + Unix SMB/CIFS implementation. + SMB torture tester + Copyright (C) Guenther Deschner 2009 + + 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 + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "nsswitch/libwbclient/wbclient.h" +#include "torture/smbtorture.h" +#include "torture/winbind/proto.h" + +#define WBC_ERROR_EQUAL(x,y) (x == y) + +#define torture_assert_wbc_equal(torture_ctx, got, expected, cmt) \ + do { wbcErr __got = got, __expected = expected; \ + if (!WBC_ERROR_EQUAL(__got, __expected)) { \ + torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", wbcErrorString(__got), wbcErrorString(__expected), cmt); \ + return false; \ + } \ + } while (0) + +#define torture_assert_wbc_ok(torture_ctx,expr,cmt) \ + torture_assert_wbc_equal(torture_ctx,expr,WBC_ERR_SUCCESS,cmt) + +static bool test_wbc_ping(struct torture_context *tctx) +{ + torture_assert_wbc_ok(tctx, wbcPing(), + "wbcPing failed"); + + return true; +} + +static bool test_wbc_library_details(struct torture_context *tctx) +{ + struct wbcLibraryDetails *details; + + torture_assert_wbc_ok(tctx, wbcLibraryDetails(&details), + "wbcLibraryDetails failed"); + torture_assert(tctx, details, + "wbcLibraryDetails returned NULL pointer"); + + wbcFreeMemory(details); + + return true; +} + +static bool test_wbc_interface_details(struct torture_context *tctx) +{ + struct wbcInterfaceDetails *details; + + torture_assert_wbc_ok(tctx, wbcInterfaceDetails(&details), + "wbcInterfaceDetails failed"); + torture_assert(tctx, details, + "wbcInterfaceDetails returned NULL pointer"); + + wbcFreeMemory(details); + + return true; +} + +static bool test_wbc_sidtypestring(struct torture_context *tctx) +{ + torture_assert_str_equal(tctx, wbcSidTypeString(WBC_SID_NAME_USE_NONE), + "SID_NONE", "SID_NONE failed"); + torture_assert_str_equal(tctx, wbcSidTypeString(WBC_SID_NAME_USER), + "SID_USER", "SID_USER failed"); + torture_assert_str_equal(tctx, wbcSidTypeString(WBC_SID_NAME_DOM_GRP), + "SID_DOM_GROUP", "SID_DOM_GROUP failed"); + torture_assert_str_equal(tctx, wbcSidTypeString(WBC_SID_NAME_DOMAIN), + "SID_DOMAIN", "SID_DOMAIN failed"); + torture_assert_str_equal(tctx, wbcSidTypeString(WBC_SID_NAME_ALIAS), + "SID_ALIAS", "SID_ALIAS failed"); + torture_assert_str_equal(tctx, wbcSidTypeString(WBC_SID_NAME_WKN_GRP), + "SID_WKN_GROUP", "SID_WKN_GROUP failed"); + torture_assert_str_equal(tctx, wbcSidTypeString(WBC_SID_NAME_DELETED), + "SID_DELETED", "SID_DELETED failed"); + torture_assert_str_equal(tctx, wbcSidTypeString(WBC_SID_NAME_INVALID), + "SID_INVALID", "SID_INVALID failed"); + torture_assert_str_equal(tctx, wbcSidTypeString(WBC_SID_NAME_UNKNOWN), + "SID_UNKNOWN", "SID_UNKNOWN failed"); + torture_assert_str_equal(tctx, wbcSidTypeString(WBC_SID_NAME_COMPUTER), + "SID_COMPUTER", "SID_COMPUTER failed"); + return true; +} + +static bool test_wbc_sidtostring(struct torture_context *tctx) +{ + struct wbcDomainSid sid; + const char *sid_string = "S-1-5-32"; + char *sid_string2; + + torture_assert_wbc_ok(tctx, wbcStringToSid(sid_string, &sid), + "wbcStringToSid failed"); + torture_assert_wbc_ok(tctx, wbcSidToString(&sid, &sid_string2), + "wbcSidToString failed"); + torture_assert_str_equal(tctx, sid_string, sid_string2, + "sid strings differ"); + + return true; +} + +static bool test_wbc_guidtostring(struct torture_context *tctx) +{ + struct wbcGuid guid; + const char *guid_string = "f7cf07b4-1487-45c7-824d-8b18cc580811"; + char *guid_string2; + + torture_assert_wbc_ok(tctx, wbcStringToGuid(guid_string, &guid), + "wbcStringToGuid failed"); + torture_assert_wbc_ok(tctx, wbcGuidToString(&guid, &guid_string2), + "wbcGuidToString failed"); + torture_assert_str_equal(tctx, guid_string, guid_string2, + "guid strings differ"); + + 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); + wbcFreeMemory(details); + + torture_assert_wbc_ok(tctx, wbcDomainInfo(domain_name, &info), + "wbcDomainInfo failed"); + torture_assert(tctx, info, + "wbcDomainInfo returned NULL pointer"); + + return true; +} + +static bool test_wbc_users(struct torture_context *tctx) +{ + const char *domain_name = NULL; + uint32_t num_users; + const char **users; + int i; + struct wbcInterfaceDetails *details; + + torture_assert_wbc_ok(tctx, wbcInterfaceDetails(&details), + "wbcInterfaceDetails failed"); + + domain_name = talloc_strdup(tctx, details->netbios_domain); + wbcFreeMemory(details); + + torture_assert_wbc_ok(tctx, wbcListUsers(domain_name, &num_users, &users), + "wbcListUsers failed"); + torture_assert(tctx, !(num_users > 0 && !users), + "wbcListUsers returned invalid results"); + + for (i=0; i < MIN(num_users,100); i++) { + + struct wbcDomainSid sid, *sids; + enum wbcSidType name_type; + char *domain; + char *name; + uint32_t num_sids; + + torture_assert_wbc_ok(tctx, wbcLookupName(domain_name, users[i], &sid, &name_type), + "wbcLookupName failed"); + torture_assert_int_equal(tctx, name_type, WBC_SID_NAME_USER, + "wbcLookupName expected WBC_SID_NAME_USER"); + torture_assert_wbc_ok(tctx, wbcLookupSid(&sid, &domain, &name, &name_type), + "wbcLookupSid failed"); + torture_assert_int_equal(tctx, name_type, WBC_SID_NAME_USER, + "wbcLookupSid expected WBC_SID_NAME_USER"); + torture_assert(tctx, name, + "wbcLookupSid returned no name"); + torture_assert_wbc_ok(tctx, wbcLookupUserSids(&sid, true, &num_sids, &sids), + "wbcLookupUserSids failed"); + } + + return true; +} + +static bool test_wbc_groups(struct torture_context *tctx) +{ + const char *domain_name = NULL; + uint32_t num_groups; + const char **groups; + int i; + struct wbcInterfaceDetails *details; + + torture_assert_wbc_ok(tctx, wbcInterfaceDetails(&details), + "wbcInterfaceDetails failed"); + + domain_name = talloc_strdup(tctx, details->netbios_domain); + wbcFreeMemory(details); + + torture_assert_wbc_ok(tctx, wbcListGroups(domain_name, &num_groups, &groups), + "wbcListGroups failed"); + torture_assert(tctx, !(num_groups > 0 && !groups), + "wbcListGroups returned invalid results"); + + for (i=0; i < MIN(num_groups,100); i++) { + + struct wbcDomainSid sid; + enum wbcSidType name_type; + char *domain; + char *name; + + torture_assert_wbc_ok(tctx, wbcLookupName(domain_name, groups[i], &sid, &name_type), + "wbcLookupName failed"); + torture_assert_wbc_ok(tctx, wbcLookupSid(&sid, &domain, &name, &name_type), + "wbcLookupSid failed"); + torture_assert(tctx, name, + "wbcLookupSid returned no name"); + } + + return true; +} + +static bool test_wbc_trusts(struct torture_context *tctx) +{ + struct wbcDomainInfo *domains; + size_t num_domains; + int i; + + torture_assert_wbc_ok(tctx, wbcListTrusts(&domains, &num_domains), + "wbcListTrusts failed"); + torture_assert(tctx, !(num_domains > 0 && !domains), + "wbcListTrusts returned invalid results"); + + for (i=0; i < MIN(num_domains,100); i++) { + + struct wbcAuthErrorInfo *error; + /* + struct wbcDomainSid sid; + enum wbcSidType name_type; + char *domain; + char *name; + */ + torture_assert_wbc_ok(tctx, wbcCheckTrustCredentials(domains[i].short_name, &error), + "wbcCheckTrustCredentials failed"); + /* + torture_assert_wbc_ok(tctx, wbcLookupName(domains[i].short_name, NULL, &sid, &name_type), + "wbcLookupName failed"); + torture_assert_int_equal(tctx, name_type, WBC_SID_NAME_DOMAIN, + "wbcLookupName expected WBC_SID_NAME_DOMAIN"); + torture_assert_wbc_ok(tctx, wbcLookupSid(&sid, &domain, &name, &name_type), + "wbcLookupSid failed"); + torture_assert_int_equal(tctx, name_type, WBC_SID_NAME_DOMAIN, + "wbcLookupSid expected WBC_SID_NAME_DOMAIN"); + torture_assert(tctx, name, + "wbcLookupSid returned no name"); + */ + } + + return true; +} + +static bool test_wbc_lookupdc(struct torture_context *tctx) +{ + const char *domain_name = NULL; + struct wbcInterfaceDetails *details; + struct wbcDomainControllerInfo *dc_info; + + torture_assert_wbc_ok(tctx, wbcInterfaceDetails(&details), + "wbcInterfaceDetails failed"); + + domain_name = talloc_strdup(tctx, details->netbios_domain); + wbcFreeMemory(details); + + torture_assert_wbc_ok(tctx, wbcLookupDomainController(domain_name, 0, &dc_info), + "wbcLookupDomainController failed"); + + return true; +} + +static bool test_wbc_lookupdcex(struct torture_context *tctx) +{ + const char *domain_name = NULL; + struct wbcInterfaceDetails *details; + struct wbcDomainControllerInfoEx *dc_info; + + torture_assert_wbc_ok(tctx, wbcInterfaceDetails(&details), + "wbcInterfaceDetails failed"); + + domain_name = talloc_strdup(tctx, details->netbios_domain); + wbcFreeMemory(details); + + torture_assert_wbc_ok(tctx, wbcLookupDomainControllerEx(domain_name, NULL, NULL, 0, &dc_info), + "wbcLookupDomainControllerEx failed"); + + return true; +} + + +struct torture_suite *torture_wbclient(void) +{ + 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, "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); + torture_suite_add_simple_test(suite, "wbcSidToString", test_wbc_sidtostring); + torture_suite_add_simple_test(suite, "wbcGuidToString", test_wbc_guidtostring); + torture_suite_add_simple_test(suite, "wbcDomainInfo", test_wbc_domain_info); + torture_suite_add_simple_test(suite, "wbcListUsers", test_wbc_users); + torture_suite_add_simple_test(suite, "wbcListGroups", test_wbc_groups); + 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); + + return suite; +} diff --git a/nsswitch/libwbclient/wb_reqtrans.c b/nsswitch/libwbclient/wb_reqtrans.c new file mode 100644 index 0000000000..6dc429bb7d --- /dev/null +++ b/nsswitch/libwbclient/wb_reqtrans.c @@ -0,0 +1,446 @@ +/* + Unix SMB/CIFS implementation. + + Async transfer of winbindd_request and _response structs + + 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 "lib/util/tevent_unix.h" +#include "nsswitch/winbind_struct_protocol.h" +#include "nsswitch/libwbclient/wbclient.h" +#include "nsswitch/libwbclient/wbc_async.h" + +/* can't use DEBUG here... */ +#define DEBUG(a,b) + +struct req_read_state { + struct winbindd_request *wb_req; + size_t max_extra_data; + ssize_t ret; +}; + +static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data); +static void wb_req_read_done(struct tevent_req *subreq); + +struct tevent_req *wb_req_read_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int fd, size_t max_extra_data) +{ + struct tevent_req *req, *subreq; + struct req_read_state *state; + + req = tevent_req_create(mem_ctx, &state, struct req_read_state); + if (req == NULL) { + return NULL; + } + state->max_extra_data = max_extra_data; + + subreq = read_packet_send(state, ev, fd, 4, wb_req_more, state); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_req_read_done, req); + return req; +} + +static ssize_t wb_req_more(uint8_t *buf, size_t buflen, void *private_data) +{ + struct req_read_state *state = talloc_get_type_abort( + private_data, struct req_read_state); + struct winbindd_request *req = (struct winbindd_request *)buf; + + if (buflen == 4) { + if (req->length != sizeof(struct winbindd_request)) { + DEBUG(0, ("wb_req_read_len: Invalid request size " + "received: %d (expected %d)\n", + (int)req->length, + (int)sizeof(struct winbindd_request))); + return -1; + } + return sizeof(struct winbindd_request) - 4; + } + + if (buflen > sizeof(struct winbindd_request)) { + /* We've been here, we're done */ + return 0; + } + + if ((state->max_extra_data != 0) + && (req->extra_len > state->max_extra_data)) { + DEBUG(3, ("Got request with %d bytes extra data on " + "unprivileged socket\n", (int)req->extra_len)); + return -1; + } + + return req->extra_len; +} + +static void wb_req_read_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct req_read_state *state = tevent_req_data( + req, struct req_read_state); + int err; + uint8_t *buf; + + state->ret = read_packet_recv(subreq, state, &buf, &err); + TALLOC_FREE(subreq); + if (state->ret == -1) { + tevent_req_error(req, err); + return; + } + + state->wb_req = (struct winbindd_request *)buf; + + if (state->wb_req->extra_len != 0) { + state->wb_req->extra_data.data = + (char *)buf + sizeof(struct winbindd_request); + } else { + state->wb_req->extra_data.data = NULL; + } + tevent_req_done(req); +} + +ssize_t wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_request **preq, int *err) +{ + struct req_read_state *state = tevent_req_data( + req, struct req_read_state); + + if (tevent_req_is_unix_error(req, err)) { + return -1; + } + *preq = talloc_move(mem_ctx, &state->wb_req); + return state->ret; +} + +struct req_write_state { + struct iovec iov[2]; + ssize_t ret; +}; + +static void wb_req_write_done(struct tevent_req *subreq); + +struct tevent_req *wb_req_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tevent_queue *queue, int fd, + struct winbindd_request *wb_req) +{ + struct tevent_req *req, *subreq; + struct req_write_state *state; + int count = 1; + + req = tevent_req_create(mem_ctx, &state, struct req_write_state); + if (req == NULL) { + return NULL; + } + + state->iov[0].iov_base = (void *)wb_req; + state->iov[0].iov_len = sizeof(struct winbindd_request); + + if (wb_req->extra_len != 0) { + state->iov[1].iov_base = (void *)wb_req->extra_data.data; + state->iov[1].iov_len = wb_req->extra_len; + count = 2; + } + + subreq = writev_send(state, ev, queue, fd, true, state->iov, count); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_req_write_done, req); + return req; +} + +static void wb_req_write_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct req_write_state *state = tevent_req_data( + req, struct req_write_state); + int err; + + state->ret = writev_recv(subreq, &err); + TALLOC_FREE(subreq); + if (state->ret < 0) { + tevent_req_error(req, err); + return; + } + tevent_req_done(req); +} + +ssize_t wb_req_write_recv(struct tevent_req *req, int *err) +{ + struct req_write_state *state = tevent_req_data( + req, struct req_write_state); + + if (tevent_req_is_unix_error(req, err)) { + return -1; + } + return state->ret; +} + +struct resp_read_state { + struct winbindd_response *wb_resp; + ssize_t ret; +}; + +static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data); +static void wb_resp_read_done(struct tevent_req *subreq); + +struct tevent_req *wb_resp_read_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, int fd) +{ + struct tevent_req *req, *subreq; + struct resp_read_state *state; + + req = tevent_req_create(mem_ctx, &state, struct resp_read_state); + if (req == NULL) { + return NULL; + } + + subreq = read_packet_send(state, ev, fd, 4, wb_resp_more, state); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_resp_read_done, req); + return req; +} + +static ssize_t wb_resp_more(uint8_t *buf, size_t buflen, void *private_data) +{ + struct winbindd_response *resp = (struct winbindd_response *)buf; + + if (buflen == 4) { + if (resp->length < sizeof(struct winbindd_response)) { + DEBUG(0, ("wb_resp_read_len: Invalid response size " + "received: %d (expected at least%d)\n", + (int)resp->length, + (int)sizeof(struct winbindd_response))); + return -1; + } + } + return resp->length - buflen; +} + +static void wb_resp_read_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct resp_read_state *state = tevent_req_data( + req, struct resp_read_state); + uint8_t *buf; + int err; + + state->ret = read_packet_recv(subreq, state, &buf, &err); + TALLOC_FREE(subreq); + if (state->ret == -1) { + tevent_req_error(req, err); + return; + } + + state->wb_resp = (struct winbindd_response *)buf; + + if (state->wb_resp->length > sizeof(struct winbindd_response)) { + state->wb_resp->extra_data.data = + (char *)buf + sizeof(struct winbindd_response); + } else { + state->wb_resp->extra_data.data = NULL; + } + tevent_req_done(req); +} + +ssize_t wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_response **presp, int *err) +{ + struct resp_read_state *state = tevent_req_data( + req, struct resp_read_state); + + if (tevent_req_is_unix_error(req, err)) { + return -1; + } + *presp = talloc_move(mem_ctx, &state->wb_resp); + return state->ret; +} + +struct resp_write_state { + struct iovec iov[2]; + ssize_t ret; +}; + +static void wb_resp_write_done(struct tevent_req *subreq); + +struct tevent_req *wb_resp_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tevent_queue *queue, int fd, + struct winbindd_response *wb_resp) +{ + struct tevent_req *req, *subreq; + struct resp_write_state *state; + int count = 1; + + req = tevent_req_create(mem_ctx, &state, struct resp_write_state); + if (req == NULL) { + return NULL; + } + + state->iov[0].iov_base = (void *)wb_resp; + state->iov[0].iov_len = sizeof(struct winbindd_response); + + if (wb_resp->length > sizeof(struct winbindd_response)) { + state->iov[1].iov_base = (void *)wb_resp->extra_data.data; + state->iov[1].iov_len = + wb_resp->length - sizeof(struct winbindd_response); + count = 2; + } + + subreq = writev_send(state, ev, queue, fd, true, state->iov, count); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_resp_write_done, req); + return req; +} + +static void wb_resp_write_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct resp_write_state *state = tevent_req_data( + req, struct resp_write_state); + int err; + + state->ret = writev_recv(subreq, &err); + TALLOC_FREE(subreq); + if (state->ret < 0) { + tevent_req_error(req, err); + return; + } + tevent_req_done(req); +} + +ssize_t wb_resp_write_recv(struct tevent_req *req, int *err) +{ + struct resp_write_state *state = tevent_req_data( + req, struct resp_write_state); + + if (tevent_req_is_unix_error(req, err)) { + return -1; + } + return state->ret; +} + +struct wb_simple_trans_state { + struct tevent_context *ev; + int fd; + struct winbindd_response *wb_resp; +}; + +static void wb_simple_trans_write_done(struct tevent_req *subreq); +static void wb_simple_trans_read_done(struct tevent_req *subreq); + +struct tevent_req *wb_simple_trans_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tevent_queue *queue, int fd, + struct winbindd_request *wb_req) +{ + struct tevent_req *req, *subreq; + struct wb_simple_trans_state *state; + + req = tevent_req_create(mem_ctx, &state, struct wb_simple_trans_state); + if (req == NULL) { + return NULL; + } + + wb_req->length = sizeof(struct winbindd_request); + + state->ev = ev; + state->fd = fd; + + subreq = wb_req_write_send(state, ev, queue, fd, wb_req); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_simple_trans_write_done, req); + + return req; +} + +static void wb_simple_trans_write_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_simple_trans_state *state = tevent_req_data( + req, struct wb_simple_trans_state); + ssize_t ret; + int err; + + ret = wb_req_write_recv(subreq, &err); + TALLOC_FREE(subreq); + if (ret == -1) { + tevent_req_error(req, err); + return; + } + subreq = wb_resp_read_send(state, state->ev, state->fd); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, wb_simple_trans_read_done, req); +} + +static void wb_simple_trans_read_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_simple_trans_state *state = tevent_req_data( + req, struct wb_simple_trans_state); + ssize_t ret; + int err; + + ret = wb_resp_read_recv(subreq, state, &state->wb_resp, &err); + TALLOC_FREE(subreq); + if (ret == -1) { + tevent_req_error(req, err); + return; + } + + tevent_req_done(req); +} + +int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_response **presponse, int *err) +{ + struct wb_simple_trans_state *state = tevent_req_data( + req, struct wb_simple_trans_state); + + if (tevent_req_is_unix_error(req, err)) { + return -1; + } + *presponse = talloc_move(mem_ctx, &state->wb_resp); + return 0; +} diff --git a/nsswitch/libwbclient/wbc_async.c b/nsswitch/libwbclient/wbc_async.c new file mode 100644 index 0000000000..181d5463e9 --- /dev/null +++ b/nsswitch/libwbclient/wbc_async.c @@ -0,0 +1,774 @@ +/* + 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 == -1) { + 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_async.h b/nsswitch/libwbclient/wbc_async.h new file mode 100644 index 0000000000..76e02cadf2 --- /dev/null +++ b/nsswitch/libwbclient/wbc_async.h @@ -0,0 +1,95 @@ +/* + Unix SMB/CIFS implementation. + Headers for the async winbind client library + 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/>. +*/ + +#ifndef _WBC_ASYNC_H_ +#define _WBC_ASYNC_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); + +struct tevent_req *wb_req_read_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int fd, size_t max_extra_data); +ssize_t wb_req_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_request **preq, int *err); + +struct tevent_req *wb_req_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tevent_queue *queue, int fd, + struct winbindd_request *wb_req); +ssize_t wb_req_write_recv(struct tevent_req *req, int *err); + +struct tevent_req *wb_resp_read_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, int fd); +ssize_t wb_resp_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_response **presp, int *err); + +struct tevent_req *wb_resp_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tevent_queue *queue, int fd, + struct winbindd_response *wb_resp); +ssize_t wb_resp_write_recv(struct tevent_req *req, int *err); + +struct tevent_req *wb_simple_trans_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct tevent_queue *queue, int fd, + struct winbindd_request *wb_req); +int wb_simple_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_response **presponse, int *err); + +#endif /*_WBC_ASYNC_H_*/ diff --git a/nsswitch/libwbclient/wbc_guid.c b/nsswitch/libwbclient/wbc_guid.c index c343e24351..d55a197973 100644 --- a/nsswitch/libwbclient/wbc_guid.c +++ b/nsswitch/libwbclient/wbc_guid.c @@ -22,6 +22,7 @@ /* Required Headers */ +#include "replace.h" #include "libwbclient.h" /* Convert a binary GUID to a character string */ diff --git a/nsswitch/libwbclient/wbc_idmap.c b/nsswitch/libwbclient/wbc_idmap.c index 5b2ab875f6..10a02fd505 100644 --- a/nsswitch/libwbclient/wbc_idmap.c +++ b/nsswitch/libwbclient/wbc_idmap.c @@ -22,6 +22,7 @@ /* Required Headers */ +#include "replace.h" #include "libwbclient.h" /* Convert a Windows SID to a Unix uid, allocating an uid if needed */ diff --git a/nsswitch/libwbclient/wbc_pam.c b/nsswitch/libwbclient/wbc_pam.c index 422665ad2e..4b187273fc 100644 --- a/nsswitch/libwbclient/wbc_pam.c +++ b/nsswitch/libwbclient/wbc_pam.c @@ -5,6 +5,7 @@ Copyright (C) Gerald (Jerry) Carter 2007 Copyright (C) Guenther Deschner 2008 + Copyright (C) Volker Lendecke 2009 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -22,6 +23,7 @@ /* Required Headers */ +#include "replace.h" #include "libwbclient.h" /* Authenticate a username/password pair */ @@ -255,7 +257,7 @@ done: } static wbcErr wbc_create_logon_info(TALLOC_CTX *mem_ctx, - const struct winbindd_response *resp, + struct winbindd_response *resp, struct wbcLogonUserInfo **_i) { wbcErr wbc_status = WBC_ERR_SUCCESS; @@ -267,7 +269,8 @@ static wbcErr wbc_create_logon_info(TALLOC_CTX *mem_ctx, wbc_status = wbc_create_auth_info(i, resp, &i->info); BAIL_ON_WBC_ERROR(wbc_status); - if (resp->data.auth.krb5ccname) { + if (resp->data.auth.krb5ccname && + strlen(resp->data.auth.krb5ccname)) { wbc_status = wbcAddNamedBlob(&i->num_blobs, &i->blobs, "krb5ccname", @@ -277,7 +280,8 @@ static wbcErr wbc_create_logon_info(TALLOC_CTX *mem_ctx, BAIL_ON_WBC_ERROR(wbc_status); } - if (resp->data.auth.unix_username) { + if (resp->data.auth.unix_username && + strlen(resp->data.auth.unix_username)) { wbc_status = wbcAddNamedBlob(&i->num_blobs, &i->blobs, "unix_username", @@ -499,6 +503,84 @@ wbcErr wbcCheckTrustCredentials(const char *domain, struct winbindd_response response; wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + if (domain) { + strncpy(request.domain_name, domain, + sizeof(request.domain_name)-1); + } + + /* Send request */ + + wbc_status = wbcRequestResponse(WINBINDD_CHECK_MACHACC, + &request, + &response); + if (response.data.auth.nt_status != 0) { + if (error) { + wbc_status = wbc_create_error_info(NULL, + &response, + error); + BAIL_ON_WBC_ERROR(wbc_status); + } + + wbc_status = WBC_ERR_AUTH_ERROR; + BAIL_ON_WBC_ERROR(wbc_status); + } + BAIL_ON_WBC_ERROR(wbc_status); + + done: + return wbc_status; +} + +/* Trigger a change of the trust credentials for a specific domain */ +wbcErr wbcChangeTrustCredentials(const char *domain, + struct wbcAuthErrorInfo **error) +{ + struct winbindd_request request; + struct winbindd_response response; + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + if (domain) { + strncpy(request.domain_name, domain, + sizeof(request.domain_name)-1); + } + + /* Send request */ + + wbc_status = wbcRequestResponse(WINBINDD_CHANGE_MACHACC, + &request, + &response); + if (response.data.auth.nt_status != 0) { + if (error) { + wbc_status = wbc_create_error_info(NULL, + &response, + error); + BAIL_ON_WBC_ERROR(wbc_status); + } + + wbc_status = WBC_ERR_AUTH_ERROR; + BAIL_ON_WBC_ERROR(wbc_status); + } + BAIL_ON_WBC_ERROR(wbc_status); + + done: + return wbc_status; +} + +/* + * Trigger a no-op NETLOGON call. Lightweight version of + * wbcCheckTrustCredentials + */ +wbcErr wbcPingDc(const char *domain, struct wbcAuthErrorInfo **error) +{ + struct winbindd_request request; + struct winbindd_response response; + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + if (domain) { /* * the current protocol doesn't support @@ -513,7 +595,7 @@ wbcErr wbcCheckTrustCredentials(const char *domain, /* Send request */ - wbc_status = wbcRequestResponse(WINBINDD_CHECK_MACHACC, + wbc_status = wbcRequestResponse(WINBINDD_PING_DC, &request, &response); if (response.data.auth.nt_status != 0) { @@ -1036,5 +1118,151 @@ wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params, struct wbcCredentialCacheInfo **info, struct wbcAuthErrorInfo **error) { - return WBC_ERR_NOT_IMPLEMENTED; + wbcErr status = WBC_ERR_UNKNOWN_FAILURE; + struct wbcCredentialCacheInfo *result = NULL; + struct winbindd_request request; + struct winbindd_response response; + struct wbcNamedBlob *initial_blob = NULL; + struct wbcNamedBlob *challenge_blob = NULL; + int i; + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + if (info != NULL) { + *info = NULL; + } + if (error != NULL) { + *error = NULL; + } + if ((params == NULL) + || (params->account_name == NULL) + || (params->level != WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP)) { + status = WBC_ERR_INVALID_PARAM; + goto fail; + } + + if (params->domain_name != NULL) { + status = wbcRequestResponse(WINBINDD_INFO, NULL, &response); + if (!WBC_ERROR_IS_OK(status)) { + goto fail; + } + snprintf(request.data.ccache_ntlm_auth.user, + sizeof(request.data.ccache_ntlm_auth.user)-1, + "%s%c%s", params->domain_name, + response.data.info.winbind_separator, + params->account_name); + } else { + strncpy(request.data.ccache_ntlm_auth.user, + params->account_name, + sizeof(request.data.ccache_ntlm_auth.user)-1); + } + request.data.ccache_ntlm_auth.uid = getuid(); + + for (i=0; i<params->num_blobs; i++) { + if (strcasecmp(params->blobs[i].name, "initial_blob") == 0) { + initial_blob = ¶ms->blobs[i]; + break; + } + if (strcasecmp(params->blobs[i].name, "challenge_blob") == 0) { + challenge_blob = ¶ms->blobs[i]; + break; + } + } + + request.data.ccache_ntlm_auth.initial_blob_len = 0; + request.data.ccache_ntlm_auth.challenge_blob_len = 0; + request.extra_len = 0; + + if (initial_blob != NULL) { + request.data.ccache_ntlm_auth.initial_blob_len = + initial_blob->blob.length; + request.extra_len += initial_blob->blob.length; + } + if (challenge_blob != NULL) { + request.data.ccache_ntlm_auth.challenge_blob_len = + challenge_blob->blob.length; + request.extra_len += challenge_blob->blob.length; + } + + if (request.extra_len != 0) { + request.extra_data.data = talloc_array( + NULL, char, request.extra_len); + if (request.extra_data.data == NULL) { + status = WBC_ERR_NO_MEMORY; + goto fail; + } + } + if (initial_blob != NULL) { + memcpy(request.extra_data.data, + initial_blob->blob.data, initial_blob->blob.length); + } + if (challenge_blob != NULL) { + memcpy(request.extra_data.data + + request.data.ccache_ntlm_auth.initial_blob_len, + challenge_blob->blob.data, + challenge_blob->blob.length); + } + + status = wbcRequestResponse(WINBINDD_CCACHE_NTLMAUTH, &request, + &response); + if (!WBC_ERROR_IS_OK(status)) { + goto fail; + } + + result = talloc(NULL, struct wbcCredentialCacheInfo); + 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; + } + status = wbcAddNamedBlob(&result->num_blobs, &result->blobs, + "auth_blob", 0, + (uint8_t *)response.extra_data.data, + response.data.ccache_ntlm_auth.auth_blob_len); + if (!WBC_ERROR_IS_OK(status)) { + goto fail; + } + status = wbcAddNamedBlob( + &result->num_blobs, &result->blobs, "session_key", 0, + response.data.ccache_ntlm_auth.session_key, + sizeof(response.data.ccache_ntlm_auth.session_key)); + if (!WBC_ERROR_IS_OK(status)) { + goto fail; + } + + if (response.extra_data.data) + free(response.extra_data.data); + *info = result; + return WBC_ERR_SUCCESS; + +fail: + TALLOC_FREE(request.extra_data.data); + if (response.extra_data.data) + free(response.extra_data.data); + talloc_free(result); + return status; +} + +/* Authenticate a user with cached credentials */ +wbcErr wbcCredentialSave(const char *user, const char *password) +{ + struct winbindd_request request; + struct winbindd_response response; + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + strncpy(request.data.ccache_save.user, user, + sizeof(request.data.ccache_save.user)-1); + strncpy(request.data.ccache_save.pass, password, + sizeof(request.data.ccache_save.pass)-1); + request.data.ccache_save.uid = getuid(); + + return wbcRequestResponse(WINBINDD_CCACHE_SAVE, &request, &response); } diff --git a/nsswitch/libwbclient/wbc_pwd.c b/nsswitch/libwbclient/wbc_pwd.c index dacd9499dd..897bf1f5c3 100644 --- a/nsswitch/libwbclient/wbc_pwd.c +++ b/nsswitch/libwbclient/wbc_pwd.c @@ -22,6 +22,7 @@ /* Required Headers */ +#include "replace.h" #include "libwbclient.h" /** @brief The maximum number of pwent structs to get from winbindd diff --git a/nsswitch/libwbclient/wbc_sid.c b/nsswitch/libwbclient/wbc_sid.c index 657c6aec7f..99c9d8e152 100644 --- a/nsswitch/libwbclient/wbc_sid.c +++ b/nsswitch/libwbclient/wbc_sid.c @@ -22,6 +22,7 @@ /* Required Headers */ +#include "replace.h" #include "libwbclient.h" @@ -813,3 +814,20 @@ wbcErr wbcGetDisplayName(const struct wbcDomainSid *sid, return wbc_status; } + +const char* wbcSidTypeString(enum wbcSidType type) +{ + switch (type) { + case WBC_SID_NAME_USE_NONE: return "SID_NONE"; + case WBC_SID_NAME_USER: return "SID_USER"; + case WBC_SID_NAME_DOM_GRP: return "SID_DOM_GROUP"; + case WBC_SID_NAME_DOMAIN: return "SID_DOMAIN"; + case WBC_SID_NAME_ALIAS: return "SID_ALIAS"; + case WBC_SID_NAME_WKN_GRP: return "SID_WKN_GROUP"; + case WBC_SID_NAME_DELETED: return "SID_DELETED"; + case WBC_SID_NAME_INVALID: return "SID_INVALID"; + case WBC_SID_NAME_UNKNOWN: return "SID_UNKNOWN"; + case WBC_SID_NAME_COMPUTER: return "SID_COMPUTER"; + default: return "Unknown type"; + } +} diff --git a/nsswitch/libwbclient/wbc_util.c b/nsswitch/libwbclient/wbc_util.c index c39023f15e..16828ae5df 100644 --- a/nsswitch/libwbclient/wbc_util.c +++ b/nsswitch/libwbclient/wbc_util.c @@ -22,6 +22,7 @@ /* Required Headers */ +#include "replace.h" #include "libwbclient.h" @@ -408,7 +409,7 @@ wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains) p = (char *)response.extra_data.data; - if (strlen(p) == 0) { + if ((p == NULL) || (strlen(p) == 0)) { /* We should always at least get back our own SAM domain */ @@ -485,7 +486,8 @@ wbcErr wbcLookupDomainController(const char *domain, ZERO_STRUCT(request); ZERO_STRUCT(response); - strncpy(request.domain_name, domain, sizeof(request.domain_name)-1); + strncpy(request.data.dsgetdcname.domain_name, domain, + sizeof(request.data.dsgetdcname.domain_name)-1); request.flags = flags; @@ -499,7 +501,7 @@ wbcErr wbcLookupDomainController(const char *domain, &response); BAIL_ON_WBC_ERROR(wbc_status); - dc->dc_name = talloc_strdup(dc, response.data.dc_name); + dc->dc_name = talloc_strdup(dc, response.data.dsgetdcname.dc_unc); BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status); *dc_info = dc; diff --git a/nsswitch/libwbclient/wbclient.c b/nsswitch/libwbclient/wbclient.c index f5c72315f2..9a1e770690 100644 --- a/nsswitch/libwbclient/wbclient.c +++ b/nsswitch/libwbclient/wbclient.c @@ -22,6 +22,9 @@ /* Required Headers */ +#include "replace.h" +#include "talloc.h" +#include "tevent.h" #include "libwbclient.h" /* From wb_common.c */ diff --git a/nsswitch/libwbclient/wbclient.h b/nsswitch/libwbclient/wbclient.h index d3c1b634f5..ac206909b0 100644 --- a/nsswitch/libwbclient/wbclient.h +++ b/nsswitch/libwbclient/wbclient.h @@ -4,6 +4,7 @@ Winbind client API Copyright (C) Gerald (Jerry) Carter 2007 + Copyright (C) Volker Lendecke 2009 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -62,9 +63,11 @@ const char *wbcErrorString(wbcErr error); * Added wbcRemoveGidMapping() * 0.3: Added wbcGetpwsid() * Added wbcGetSidAliases() + * 0.4: Added wbcSidTypeString() + * 0.5: Added wbcChangeTrustCredentials() **/ #define WBCLIENT_MAJOR_VERSION 0 -#define WBCLIENT_MINOR_VERSION 3 +#define WBCLIENT_MINOR_VERSION 5 #define WBCLIENT_VENDOR_VERSION "Samba libwbclient" struct wbcLibraryDetails { uint16_t major_version; @@ -507,6 +510,15 @@ void wbcFreeMemory(void*); */ /** + * @brief Get a string representation of the SID type + * + * @param type type of the SID + * + * @return string representation of the SID type + */ +const char* wbcSidTypeString(enum wbcSidType type); + +/** * @brief Convert a binary SID to a character string * * @param sid Binary Security Identifier @@ -1141,6 +1153,16 @@ wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params, struct wbcCredentialCacheInfo **info, struct wbcAuthErrorInfo **error); +/** + * @brief Save a password with winbind for doing wbcCredentialCache() later + * + * @param *user Username + * @param *password Password + * + * @return #wbcErr + **/ +wbcErr wbcCredentialSave(const char *user, const char *password); + /********************************************************** * Resolve functions **********************************************************/ @@ -1173,6 +1195,29 @@ wbcErr wbcResolveWinsByIP(const char *ip, char **name); /** * @brief Trigger a verification of the trust credentials of a specific domain * + * @param *domain The name of the domain. + * @param error Output details on WBC_ERR_AUTH_ERROR + * + * @return #wbcErr + **/ +wbcErr wbcCheckTrustCredentials(const char *domain, + struct wbcAuthErrorInfo **error); + +/** + * @brief Trigger a change of the trust credentials for a specific domain + * + * @param *domain The name of the domain. + * @param error Output details on WBC_ERR_AUTH_ERROR + * + * @return #wbcErr + **/ +wbcErr wbcChangeTrustCredentials(const char *domain, + struct wbcAuthErrorInfo **error); + +/** + * @brief Trigger a no-op call through the NETLOGON pipe. Low-cost + * version of wbcCheckTrustCredentials + * * @param *domain The name of the domain, only NULL for the default domain is * supported yet. Other values than NULL will result in * WBC_ERR_NOT_IMPLEMENTED. @@ -1180,8 +1225,7 @@ wbcErr wbcResolveWinsByIP(const char *ip, char **name); * * @return #wbcErr **/ -wbcErr wbcCheckTrustCredentials(const char *domain, - struct wbcAuthErrorInfo **error); +wbcErr wbcPingDc(const char *domain, struct wbcAuthErrorInfo **error); /********************************************************** * Helper functions diff --git a/nsswitch/libwbclient/wbclient_internal.h b/nsswitch/libwbclient/wbclient_internal.h index fc03c5409b..2d103ab3df 100644 --- a/nsswitch/libwbclient/wbclient_internal.h +++ b/nsswitch/libwbclient/wbclient_internal.h @@ -28,5 +28,4 @@ wbcErr wbcRequestResponse(int cmd, struct winbindd_request *request, struct winbindd_response *response); - #endif /* _WBCLIENT_INTERNAL_H */ diff --git a/nsswitch/nsstest.h b/nsswitch/nsstest.h index e69f17c857..53adce5500 100644 --- a/nsswitch/nsstest.h +++ b/nsswitch/nsstest.h @@ -3,17 +3,21 @@ nss includes for the nss tester Copyright (C) Kai Blin 2007 - 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 - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. + ** NOTE! The following LGPL license applies to the nsstest + ** header. This does NOT imply that all of Samba is released + ** under the LGPL - This program is distributed in the hope that it will be useful, + 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 General Public License for more details. + 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 General Public License + 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/>. */ diff --git a/nsswitch/pam_winbind.c b/nsswitch/pam_winbind.c index b411eb7f77..b80203674b 100644 --- a/nsswitch/pam_winbind.c +++ b/nsswitch/pam_winbind.c @@ -11,6 +11,8 @@ */ #include "pam_winbind.h" +#define CONST_DISCARD(type,ptr) ((type)(void *)ptr) + static int wbc_error_to_pam_error(wbcErr status) { @@ -410,49 +412,51 @@ static int _pam_parse(const pam_handle_t *pamh, config_file = PAM_WINBIND_CONFIG_FILE; } - d = iniparser_load(config_file); + d = iniparser_load(CONST_DISCARD(char *, config_file)); if (d == NULL) { goto config_from_pam; } - if (iniparser_getboolean(d, "global:debug", false)) { + if (iniparser_getboolean(d, CONST_DISCARD(char *, "global:debug"), false)) { ctrl |= WINBIND_DEBUG_ARG; } - if (iniparser_getboolean(d, "global:debug_state", false)) { + if (iniparser_getboolean(d, CONST_DISCARD(char *, "global:debug_state"), false)) { ctrl |= WINBIND_DEBUG_STATE; } - if (iniparser_getboolean(d, "global:cached_login", false)) { + if (iniparser_getboolean(d, CONST_DISCARD(char *, "global:cached_login"), false)) { ctrl |= WINBIND_CACHED_LOGIN; } - if (iniparser_getboolean(d, "global:krb5_auth", false)) { + if (iniparser_getboolean(d, CONST_DISCARD(char *, "global:krb5_auth"), false)) { ctrl |= WINBIND_KRB5_AUTH; } - if (iniparser_getboolean(d, "global:silent", false)) { + if (iniparser_getboolean(d, CONST_DISCARD(char *, "global:silent"), false)) { ctrl |= WINBIND_SILENT; } - if (iniparser_getstr(d, "global:krb5_ccache_type") != NULL) { + if (iniparser_getstr(d, CONST_DISCARD(char *, "global:krb5_ccache_type")) != NULL) { ctrl |= WINBIND_KRB5_CCACHE_TYPE; } - if ((iniparser_getstr(d, "global:require-membership-of") != NULL) || - (iniparser_getstr(d, "global:require_membership_of") != NULL)) { + if ((iniparser_getstr(d, CONST_DISCARD(char *, "global:require-membership-of")) + != NULL) || + (iniparser_getstr(d, CONST_DISCARD(char *, "global:require_membership_of")) + != NULL)) { ctrl |= WINBIND_REQUIRED_MEMBERSHIP; } - if (iniparser_getboolean(d, "global:try_first_pass", false)) { + if (iniparser_getboolean(d, CONST_DISCARD(char *, "global:try_first_pass"), false)) { ctrl |= WINBIND_TRY_FIRST_PASS_ARG; } - if (iniparser_getint(d, "global:warn_pwd_expire", 0)) { + if (iniparser_getint(d, CONST_DISCARD(char *, "global:warn_pwd_expire"), 0)) { ctrl |= WINBIND_WARN_PWD_EXPIRE; } - if (iniparser_getboolean(d, "global:mkhomedir", false)) { + if (iniparser_getboolean(d, CONST_DISCARD(char *, "global:mkhomedir"), false)) { ctrl |= WINBIND_MKHOMEDIR; } @@ -803,6 +807,43 @@ static int wbc_auth_error_to_pam_error(struct pwb_context *ctx, return pam_winbind_request_log(ctx, ret, username, fn); } +#if defined(HAVE_PAM_RADIO_TYPE) +static bool _pam_winbind_change_pwd(struct pwb_context *ctx) +{ + struct pam_message msg, *pmsg; + struct pam_response *resp = NULL; + const char *prompt; + int ret; + bool retval = false; + prompt = _("Do you want to change your password now?"); + pmsg = &msg; + msg.msg_style = PAM_RADIO_TYPE; + msg.msg = prompt; + ret = converse(ctx->pamh, 1, &pmsg, &resp); + if (resp == NULL) { + if (ret == PAM_SUCCESS) { + _pam_log(ctx, LOG_CRIT, "pam_winbind: system error!\n"); + return false; + } + } + if (ret != PAM_SUCCESS) { + return false; + } + _pam_log(ctx, LOG_CRIT, "Received [%s] reply from application.\n", resp->resp); + + if (strcasecmp(resp->resp, "yes") == 0) { + retval = true; + } + + _pam_drop_reply(resp, 1); + return retval; +} +#else +static bool _pam_winbind_change_pwd(struct pwb_context *ctx) +{ + return false; +} +#endif /** * send a password expiry message if required @@ -819,15 +860,22 @@ static bool _pam_send_password_expiry_message(struct pwb_context *ctx, time_t next_change, time_t now, int warn_pwd_expire, - bool *already_expired) + bool *already_expired, + bool *change_pwd) { int days = 0; struct tm tm_now, tm_next_change; + bool retval = false; + int ret; if (already_expired) { *already_expired = false; } + if (change_pwd) { + *change_pwd = false; + } + if (next_change <= now) { PAM_WB_REMARK_DIRECT(ctx, "NT_STATUS_PASSWORD_EXPIRED"); if (already_expired) { @@ -850,15 +898,61 @@ static bool _pam_send_password_expiry_message(struct pwb_context *ctx, (tm_now.tm_yday+tm_now.tm_year*365); if (days == 0) { - _make_remark(ctx, PAM_TEXT_INFO, - _("Your password expires today")); + ret = _make_remark(ctx, PAM_TEXT_INFO, + _("Your password expires today.\n")); + + /* + * If change_pwd and already_expired is null. + * We are just sending a notification message. + * We don't expect any response in this case. + */ + + if (!change_pwd && !already_expired) { + return true; + } + + /* + * successfully sent the warning message. + * Give the user a chance to change pwd. + */ + if (ret == PAM_SUCCESS) { + if (change_pwd) { + retval = _pam_winbind_change_pwd(ctx); + if (retval) { + *change_pwd = true; + } + } + } return true; } if (days > 0 && days < warn_pwd_expire) { - _make_remark_format(ctx, PAM_TEXT_INFO, - _("Your password will expire in %d %s"), - days, (days > 1) ? _("days"):_("day")); + + ret = _make_remark_format(ctx, PAM_TEXT_INFO, + _("Your password will expire in %d %s.\n"), + days, (days > 1) ? _("days"):_("day")); + /* + * If change_pwd and already_expired is null. + * We are just sending a notification message. + * We don't expect any response in this case. + */ + + if (!change_pwd && !already_expired) { + return true; + } + + /* + * successfully sent the warning message. + * Give the user a chance to change pwd. + */ + if (ret == PAM_SUCCESS) { + if (change_pwd) { + retval = _pam_winbind_change_pwd(ctx); + if (retval) { + *change_pwd = true; + } + } + } return true; } @@ -879,7 +973,8 @@ static void _pam_warn_password_expiry(struct pwb_context *ctx, const struct wbcAuthUserInfo *info, const struct wbcUserPasswordPolicyInfo *policy, int warn_pwd_expire, - bool *already_expired) + bool *already_expired, + bool *change_pwd) { time_t now = time(NULL); time_t next_change = 0; @@ -892,6 +987,10 @@ static void _pam_warn_password_expiry(struct pwb_context *ctx, *already_expired = false; } + if (change_pwd) { + *change_pwd = false; + } + /* accounts with WBC_ACB_PWNOEXP set never receive a warning */ if (info->acct_flags & WBC_ACB_PWNOEXP) { return; @@ -907,7 +1006,8 @@ static void _pam_warn_password_expiry(struct pwb_context *ctx, if (_pam_send_password_expiry_message(ctx, next_change, now, warn_pwd_expire, - already_expired)) { + already_expired, + change_pwd)) { return; } @@ -923,7 +1023,8 @@ static void _pam_warn_password_expiry(struct pwb_context *ctx, if (_pam_send_password_expiry_message(ctx, next_change, now, warn_pwd_expire, - already_expired)) { + already_expired, + change_pwd)) { return; } @@ -1752,11 +1853,13 @@ static int winbind_auth_request(struct pwb_context *ctx, if ((ret == PAM_SUCCESS) && user_info && policy && info) { bool already_expired = false; + bool change_pwd = false; /* warn a user if the password is about to expire soon */ _pam_warn_password_expiry(ctx, user_info, policy, warn_pwd_expire, - &already_expired); + &already_expired, + &change_pwd); if (already_expired == true) { @@ -1766,15 +1869,20 @@ static int winbind_auth_request(struct pwb_context *ctx, "Password has expired " "(Password was last set: %lld, " "the policy says it should expire here " - "%lld (now it's: %lu))\n", + "%lld (now it's: %ld))\n", (long long int)last_set, (long long int)last_set + policy->expire, - time(NULL)); + (long)time(NULL)); return PAM_AUTHTOK_EXPIRED; } + if (change_pwd) { + ret = PAM_NEW_AUTHTOK_REQD; + goto done; + } + /* inform about logon type */ _pam_warn_logon_type(ctx, user, user_info->user_flags); @@ -2331,7 +2439,6 @@ static char* winbind_upn_to_username(struct pwb_context *ctx, if (!name) { return NULL; } - if ((p = strchr(name, '@')) != NULL) { *p = 0; domain = p + 1; @@ -3132,7 +3239,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, * expire soon */ _pam_warn_password_expiry(ctx, user_info, policy, warn_pwd_expire, - NULL); + NULL, NULL); /* set some info3 info for other modules in the * stack */ diff --git a/nsswitch/tests/test_wbinfo.sh b/nsswitch/tests/test_wbinfo.sh index 2e94c24640..8d8f116e70 100755 --- a/nsswitch/tests/test_wbinfo.sh +++ b/nsswitch/tests/test_wbinfo.sh @@ -150,8 +150,10 @@ testfail "wbinfo -Y against $TARGET using invalid SID" $wbinfo -Y "S-1-22-1-3000 testit "wbinfo -t against $TARGET" $wbinfo -t || failed=`expr $failed + 1` -testit "wbinfo --trusted-domains against $TARGET" $wbinfo --trusted-domains || failed=`expr $failed + 1` -testit "wbinfo --all-domains against $TARGET" $wbinfo --all-domains || failed=`expr $failed + 1` +#didn't really work anyway +knownfail "wbinfo --trusted-domains against $TARGET" $wbinfo --trusted-domains || failed=`expr $failed + 1` +knownfail "wbinfo --all-domains against $TARGET" $wbinfo --all-domains || failed=`expr $failed + 1` + testit "wbinfo --own-domain against $TARGET" $wbinfo --own-domain || failed=`expr $failed + 1` echo "test: wbinfo --own-domain against $TARGET check output" @@ -165,7 +167,9 @@ fi # this does not work knownfail "wbinfo --sequence against $TARGET" $wbinfo --sequence -knownfail "wbinfo -D against $TARGET" $wbinfo -D $DOMAIN || failed=`expr $failed + 1` + +# this is stubbed out now +testit "wbinfo -D against $TARGET" $wbinfo -D $DOMAIN || failed=`expr $failed + 1` testit "wbinfo -i against $TARGET" $wbinfo -i "$DOMAIN/$USERNAME" || failed=`expr $failed + 1` diff --git a/nsswitch/wbinfo.c b/nsswitch/wbinfo.c index d12e512166..a43ce8f4c9 100644 --- a/nsswitch/wbinfo.c +++ b/nsswitch/wbinfo.c @@ -4,7 +4,8 @@ Winbind status program. Copyright (C) Tim Potter 2000-2003 - Copyright (C) Andrew Bartlett 2002 + Copyright (C) Andrew Bartlett 2002-2007 + Copyright (C) Volker Lendecke 2009 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 @@ -23,9 +24,16 @@ #include "includes.h" #include "winbind_client.h" #include "libwbclient/wbclient.h" +#include "lib/popt/popt.h" +#include "../libcli/auth/libcli_auth.h" +#if !(_SAMBA_VERSION_) < 4 +#include "lib/cmdline/popt_common.h" +#endif +#ifdef DBGC_CLASS #undef DBGC_CLASS #define DBGC_CLASS DBGC_WINBIND +#endif static struct wbcInterfaceDetails *init_interface_details(void) { @@ -38,13 +46,14 @@ 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"); + d_fprintf(stderr, "could not obtain winbind interface " + "details!\n"); } return details; } -static char winbind_separator_int(bool strict) +static char winbind_separator(void) { struct wbcInterfaceDetails *details; static bool got_sep; @@ -57,11 +66,7 @@ static char winbind_separator_int(bool strict) if (!details) { d_fprintf(stderr, "could not obtain winbind separator!\n"); - if (strict) { - return 0; - } - /* HACK: (this module should not call lp_ funtions) */ - return *lp_winbind_separator(); + return 0; } sep = details->winbind_separator; @@ -69,21 +74,12 @@ static char winbind_separator_int(bool strict) if (!sep) { d_fprintf(stderr, "winbind separator was NULL!\n"); - if (strict) { - return 0; - } - /* HACK: (this module should not call lp_ funtions) */ - sep = *lp_winbind_separator(); + return 0; } return sep; } -static char winbind_separator(void) -{ - return winbind_separator_int(false); -} - static const char *get_winbind_domain(void) { static struct wbcInterfaceDetails *details; @@ -92,14 +88,26 @@ static const char *get_winbind_domain(void) if (!details) { d_fprintf(stderr, "could not obtain winbind domain name!\n"); - - /* HACK: (this module should not call lp_ functions) */ - return lp_workgroup(); + return 0; } return details->netbios_domain; } +static const char *get_winbind_netbios_name(void) +{ + static struct wbcInterfaceDetails *details; + + details = init_interface_details(); + + if (!details) { + d_fprintf(stderr, "could not obtain winbind netbios name!\n"); + return 0; + } + + return details->netbios_name; +} + /* Copy of parse_domain_user from winbindd_util.c. Parse a string of the form DOMAIN/user into a domain and a user */ @@ -232,17 +240,25 @@ static bool wbinfo_get_groupinfo(const char *group) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct group *grp; + char **mem; wbc_status = wbcGetgrnam(group, &grp); if (!WBC_ERROR_IS_OK(wbc_status)) { return false; } - d_printf("%s:%s:%u\n", + d_printf("%s:%s:%u:", grp->gr_name, grp->gr_passwd, (unsigned int)grp->gr_gid); + mem = grp->gr_mem; + while (*mem != NULL) { + d_printf("%s%s", *mem, *(mem+1) != NULL ? "," : ""); + mem += 1; + } + d_printf("\n"); + wbcFreeMemory(grp); return true; @@ -253,17 +269,25 @@ static bool wbinfo_get_gidinfo(int gid) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct group *grp; + char **mem; wbc_status = wbcGetgrgid(gid, &grp); if (!WBC_ERROR_IS_OK(wbc_status)) { return false; } - d_printf("%s:%s:%u\n", + d_printf("%s:%s:%u:", grp->gr_name, grp->gr_passwd, (unsigned int)grp->gr_gid); + mem = grp->gr_mem; + while (*mem != NULL) { + d_printf("%s%s", *mem, *(mem+1) != NULL ? "," : ""); + mem += 1; + } + d_printf("\n"); + wbcFreeMemory(grp); return true; @@ -549,7 +573,8 @@ static bool wbinfo_list_own_domain(void) /* show sequence numbers */ static bool wbinfo_show_sequence(const char *domain) { - d_printf("This command has been deprecated. Please use the --online-status option instead.\n"); + d_printf("This command has been deprecated. Please use the " + "--online-status option instead.\n"); return false; } @@ -575,7 +600,8 @@ static bool wbinfo_show_onlinestatus(const char *domain) } } - is_offline = (domain_list[i].domain_flags & WBC_DOMINFO_DOMAIN_OFFLINE); + is_offline = (domain_list[i].domain_flags & + WBC_DOMINFO_DOMAIN_OFFLINE); d_printf("%s : %s\n", domain_list[i].short_name, @@ -594,7 +620,7 @@ static bool wbinfo_domain_info(const char *domain) struct wbcDomainInfo *dinfo = NULL; char *sid_str = NULL; - if ((domain == NULL) || (strequal(domain, ".")) || (domain[0] == '\0')) { + if ((domain == NULL) || (strequal(domain, ".")) || (domain[0] == '\0')){ domain = get_winbind_domain(); } @@ -621,10 +647,12 @@ static bool wbinfo_domain_info(const char *domain) d_printf("Active Directory : %s\n", (dinfo->domain_flags & WBC_DOMINFO_DOMAIN_AD) ? "Yes" : "No"); d_printf("Native : %s\n", - (dinfo->domain_flags & WBC_DOMINFO_DOMAIN_NATIVE) ? "Yes" : "No"); + (dinfo->domain_flags & WBC_DOMINFO_DOMAIN_NATIVE) ? + "Yes" : "No"); d_printf("Primary : %s\n", - (dinfo->domain_flags & WBC_DOMINFO_DOMAIN_PRIMARY) ? "Yes" : "No"); + (dinfo->domain_flags & WBC_DOMINFO_DOMAIN_PRIMARY) ? + "Yes" : "No"); wbcFreeMemory(sid_str); wbcFreeMemory(dinfo); @@ -645,9 +673,9 @@ static bool wbinfo_getdcname(const char *domain_name) /* Send request */ - if (winbindd_request_response(WINBINDD_GETDCNAME, &request, &response) != - NSS_STATUS_SUCCESS) { - d_fprintf(stderr, "Could not get dc name for %s\n", domain_name); + if (winbindd_request_response(WINBINDD_GETDCNAME, &request, + &response) != NSS_STATUS_SUCCESS) { + d_fprintf(stderr, "Could not get dc name for %s\n",domain_name); return false; } @@ -661,50 +689,107 @@ static bool wbinfo_getdcname(const char *domain_name) /* Find a DC */ static bool wbinfo_dsgetdcname(const char *domain_name, uint32_t flags) { - struct winbindd_request request; - struct winbindd_response response; + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + struct wbcDomainControllerInfoEx *dc_info; + char *str = NULL; - ZERO_STRUCT(request); - ZERO_STRUCT(response); + wbc_status = wbcLookupDomainControllerEx(domain_name, NULL, NULL, + flags | DS_DIRECTORY_SERVICE_REQUIRED, + &dc_info); + if (!WBC_ERROR_IS_OK(wbc_status)) { + printf("Could not find dc for %s\n", domain_name); + return false; + } - fstrcpy(request.data.dsgetdcname.domain_name, domain_name); - request.data.dsgetdcname.flags = flags; + wbcGuidToString(dc_info->domain_guid, &str); - request.flags |= DS_DIRECTORY_SERVICE_REQUIRED; + d_printf("%s\n", dc_info->dc_unc); + d_printf("%s\n", dc_info->dc_address); + d_printf("%d\n", dc_info->dc_address_type); + d_printf("%s\n", str); + d_printf("%s\n", dc_info->domain_name); + d_printf("%s\n", dc_info->forest_name); + d_printf("0x%08x\n", dc_info->dc_flags); + d_printf("%s\n", dc_info->dc_site_name); + d_printf("%s\n", dc_info->client_site_name); - /* Send request */ + return true; +} + +/* Check trust account password */ + +static bool wbinfo_check_secret(const char *domain) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + struct wbcAuthErrorInfo *error = NULL; + const char *domain_name; + + if (domain) { + domain_name = domain; + } else { + domain_name = get_winbind_domain(); + } - if (winbindd_request_response(WINBINDD_DSGETDCNAME, &request, &response) != - NSS_STATUS_SUCCESS) { - d_fprintf(stderr, "Could not find dc for %s\n", domain_name); + wbc_status = wbcCheckTrustCredentials(domain_name, &error); + + d_printf("checking the trust secret for domain %s via RPC calls %s\n", + domain_name, + WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed"); + + if (wbc_status == WBC_ERR_AUTH_ERROR) { + d_fprintf(stderr, "error code was %s (0x%x)\n", + error->nt_string, error->nt_status); + wbcFreeMemory(error); + } + if (!WBC_ERROR_IS_OK(wbc_status)) { return false; } - /* Display response */ + return true; +} - d_printf("%s\n", response.data.dsgetdcname.dc_unc); - d_printf("%s\n", response.data.dsgetdcname.dc_address); - d_printf("%d\n", response.data.dsgetdcname.dc_address_type); - d_printf("%s\n", response.data.dsgetdcname.domain_guid); - d_printf("%s\n", response.data.dsgetdcname.domain_name); - d_printf("%s\n", response.data.dsgetdcname.forest_name); - d_printf("0x%08x\n", response.data.dsgetdcname.dc_flags); - d_printf("%s\n", response.data.dsgetdcname.dc_site_name); - d_printf("%s\n", response.data.dsgetdcname.client_site_name); +/* Change trust account password */ + +static bool wbinfo_change_secret(const char *domain) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + struct wbcAuthErrorInfo *error = NULL; + const char *domain_name; + + if (domain) { + domain_name = domain; + } else { + domain_name = get_winbind_domain(); + } + + wbc_status = wbcChangeTrustCredentials(domain_name, &error); + + d_printf("changing the trust secret for domain %s via RPC calls %s\n", + domain_name, + WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed"); + + if (wbc_status == WBC_ERR_AUTH_ERROR) { + d_fprintf(stderr, "error code was %s (0x%x)\n", + error->nt_string, error->nt_status); + wbcFreeMemory(error); + } + if (!WBC_ERROR_IS_OK(wbc_status)) { + return false; + } return true; } -/* Check trust account password */ +/* Check DC connection */ -static bool wbinfo_check_secret(void) +static bool wbinfo_ping_dc(void) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct wbcAuthErrorInfo *error = NULL; - wbc_status = wbcCheckTrustCredentials(NULL, &error); + wbc_status = wbcPingDc(NULL, &error); - d_printf("checking the trust secret via RPC calls %s\n", + d_printf("checking the NETLOGON dc connection %s\n", WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed"); if (wbc_status == WBC_ERR_AUTH_ERROR) { @@ -1038,13 +1123,13 @@ static bool wbinfo_lookuprids(const char *domain, const char *arg) enum wbcSidType *types = NULL; size_t i; int num_rids; - uint32 *rids = NULL; + uint32_t *rids = NULL; const char *p; char *ridstr; TALLOC_CTX *mem_ctx = NULL; bool ret = false; - if ((domain == NULL) || (strequal(domain, ".")) || (domain[0] == '\0')) { + if ((domain == NULL) || (strequal(domain, ".")) || (domain[0] == '\0')){ domain = get_winbind_domain(); } @@ -1068,8 +1153,13 @@ static bool wbinfo_lookuprids(const char *domain, const char *arg) p = arg; while (next_token_talloc(mem_ctx, &p, &ridstr, " ,\n")) { - uint32 rid = strtoul(ridstr, NULL, 10); - ADD_TO_ARRAY(mem_ctx, uint32, rid, &rids, &num_rids); + uint32_t rid = strtoul(ridstr, NULL, 10); + rids = talloc_realloc(mem_ctx, rids, uint32_t, num_rids + 1); + if (rids == NULL) { + d_printf("talloc_realloc failed\n"); + } + rids[num_rids] = rid; + num_rids += 1; } if (rids == NULL) { @@ -1089,7 +1179,7 @@ static bool wbinfo_lookuprids(const char *domain, const char *arg) for (i=0; i<num_rids; i++) { d_printf("%8d: %s (%s)\n", rids[i], names[i], - sid_type_lookup(types[i])); + wbcSidTypeString(types[i])); } ret = true; @@ -1139,20 +1229,21 @@ static bool wbinfo_lookupname(const char *full_name) /* Display response */ - d_printf("%s %s (%d)\n", sid_str, sid_type_lookup(type), type); + d_printf("%s %s (%d)\n", sid_str, wbcSidTypeString(type), type); wbcFreeMemory(sid_str); return true; } -static char *wbinfo_prompt_pass(const char *prefix, +static char *wbinfo_prompt_pass(TALLOC_CTX *mem_ctx, + const char *prefix, const char *username) { char *prompt; const char *ret = NULL; - prompt = talloc_asprintf(talloc_tos(), "Enter %s's ", username); + prompt = talloc_asprintf(mem_ctx, "Enter %s's ", username); if (!prompt) { return NULL; } @@ -1170,73 +1261,124 @@ static char *wbinfo_prompt_pass(const char *prefix, ret = getpass(prompt); TALLOC_FREE(prompt); - return SMB_STRDUP(ret); + return talloc_strdup(mem_ctx, ret); } /* Authenticate a user with a plaintext password */ -static bool wbinfo_auth_krb5(char *username, const char *cctype, uint32 flags) +static bool wbinfo_auth_krb5(char *username, const char *cctype, uint32_t flags) { - struct winbindd_request request; - struct winbindd_response response; - NSS_STATUS result; - char *p; - char *password; - - /* Send off request */ - - ZERO_STRUCT(request); - ZERO_STRUCT(response); + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + char *s = NULL; + char *p = NULL; + char *password = NULL; + char *name = NULL; + char *local_cctype = NULL; + uid_t uid; + struct wbcLogonUserParams params; + struct wbcLogonUserInfo *info; + struct wbcAuthErrorInfo *error; + struct wbcUserPasswordPolicyInfo *policy; + TALLOC_CTX *frame = talloc_tos(); - p = strchr(username, '%'); + if ((s = talloc_strdup(frame, username)) == NULL) { + return false; + } - if (p) { + if ((p = strchr(s, '%')) != NULL) { *p = 0; - fstrcpy(request.data.auth.user, username); - fstrcpy(request.data.auth.pass, p + 1); - *p = '%'; + p++; + password = talloc_strdup(frame, p); } else { - fstrcpy(request.data.auth.user, username); - password = wbinfo_prompt_pass(NULL, username); - fstrcpy(request.data.auth.pass, password); - SAFE_FREE(password); + password = wbinfo_prompt_pass(frame, NULL, username); } - request.flags = flags; + local_cctype = talloc_strdup(frame, cctype); - fstrcpy(request.data.auth.krb5_cc_type, cctype); + name = s; - request.data.auth.uid = geteuid(); + uid = geteuid(); - result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response); + params.username = name; + params.password = password; + params.num_blobs = 0; + params.blobs = NULL; - /* Display response */ + wbc_status = wbcAddNamedBlob(¶ms.num_blobs, + ¶ms.blobs, + "flags", + 0, + (uint8_t *)&flags, + sizeof(flags)); + if (!WBC_ERROR_IS_OK(wbc_status)) { + goto done; + } - d_printf("plaintext kerberos password authentication for [%s] %s (requesting cctype: %s)\n", - username, (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed", cctype); + wbc_status = wbcAddNamedBlob(¶ms.num_blobs, + ¶ms.blobs, + "user_uid", + 0, + (uint8_t *)&uid, + sizeof(uid)); + if (!WBC_ERROR_IS_OK(wbc_status)) { + goto done; + } - if (response.data.auth.nt_status) - d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", - response.data.auth.nt_status_string, - response.data.auth.nt_status, - response.data.auth.error_string); + wbc_status = wbcAddNamedBlob(¶ms.num_blobs, + ¶ms.blobs, + "krb5_cc_type", + 0, + (uint8_t *)local_cctype, + strlen(cctype)+1); + if (!WBC_ERROR_IS_OK(wbc_status)) { + goto done; + } + + wbc_status = wbcLogonUser(¶ms, &info, &error, &policy); + + d_printf("plaintext kerberos password authentication for [%s] %s " + "(requesting cctype: %s)\n", + username, WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed", + cctype); - if (result == NSS_STATUS_SUCCESS) { + if (error) { + d_fprintf(stderr, + "error code was %s (0x%x)\nerror messsage was: %s\n", + error->nt_string, + error->nt_status, + error->display_string); + } - if (request.flags & WBFLAG_PAM_INFO3_TEXT) { - if (response.data.auth.info3.user_flgs & NETLOGON_CACHED_ACCOUNT) { - d_printf("user_flgs: NETLOGON_CACHED_ACCOUNT\n"); + if (WBC_ERROR_IS_OK(wbc_status)) { + if (flags & WBFLAG_PAM_INFO3_TEXT) { + if (info && info->info && info->info->user_flags & + NETLOGON_CACHED_ACCOUNT) { + d_printf("user_flgs: " + "NETLOGON_CACHED_ACCOUNT\n"); } } - if (response.data.auth.krb5ccname[0] != '\0') { - d_printf("credentials were put in: %s\n", response.data.auth.krb5ccname); + if (info) { + int i; + for (i=0; i < info->num_blobs; i++) { + if (strequal(info->blobs[i].name, + "krb5ccname")) { + d_printf("credentials were put " + "in: %s\n", + (const char *) + info->blobs[i].blob.data); + break; + } + } } else { d_printf("no credentials cached\n"); } } + done: - return result == NSS_STATUS_SUCCESS; + wbcFreeMemory(params.blobs); + + return WBC_ERROR_IS_OK(wbc_status); } /* Authenticate a user with a plaintext password */ @@ -1248,17 +1390,18 @@ static bool wbinfo_auth(char *username) char *p = NULL; char *password = NULL; char *name = NULL; + TALLOC_CTX *frame = talloc_tos(); - if ((s = SMB_STRDUP(username)) == NULL) { + if ((s = talloc_strdup(frame, username)) == NULL) { return false; } if ((p = strchr(s, '%')) != NULL) { *p = 0; p++; - password = SMB_STRDUP(p); + password = talloc_strdup(frame, p); } else { - password = wbinfo_prompt_pass(NULL, username); + password = wbinfo_prompt_pass(frame, NULL, username); } name = s; @@ -1270,21 +1413,19 @@ 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", + d_fprintf(stderr, + "error code was %s (0x%x)\nerror messsage was: %s\n", response.data.auth.nt_status_string, response.data.auth.nt_status, response.data.auth.error_string); #endif - SAFE_FREE(s); - SAFE_FREE(password); - return WBC_ERROR_IS_OK(wbc_status); } /* Authenticate a user with a challenge/response */ -static bool wbinfo_auth_crap(char *username) +static bool wbinfo_auth_crap(char *username, bool use_ntlmv2, bool use_lanman) { wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; struct wbcAuthUserParams params; @@ -1296,14 +1437,15 @@ static bool wbinfo_auth_crap(char *username) fstring name_domain; char *pass; char *p; + TALLOC_CTX *frame = talloc_tos(); p = strchr(username, '%'); if (p) { *p = 0; - pass = SMB_STRDUP(p + 1); + pass = talloc_strdup(frame, p + 1); } else { - pass = wbinfo_prompt_pass(NULL, username); + pass = wbinfo_prompt_pass(frame, NULL, username); } parse_wbinfo_domain_user(username, name_domain, name_user); @@ -1320,31 +1462,35 @@ static bool wbinfo_auth_crap(char *username) generate_random_buffer(params.password.response.challenge, 8); - if (lp_client_ntlmv2_auth()) { + if (use_ntlmv2) { DATA_BLOB server_chal; DATA_BLOB names_blob; server_chal = data_blob(params.password.response.challenge, 8); /* Pretend this is a login to 'us', for blob purposes */ - names_blob = NTLMv2_generate_names_blob(global_myname(), lp_workgroup()); + names_blob = NTLMv2_generate_names_blob(NULL, + get_winbind_netbios_name(), + get_winbind_domain()); - if (!SMBNTLMv2encrypt(name_user, name_domain, pass, &server_chal, + if (!SMBNTLMv2encrypt(NULL, name_user, name_domain, pass, + &server_chal, &names_blob, - &lm, &nt, NULL)) { + &lm, &nt, NULL, NULL)) { data_blob_free(&names_blob); data_blob_free(&server_chal); - SAFE_FREE(pass); + TALLOC_FREE(pass); return false; } data_blob_free(&names_blob); data_blob_free(&server_chal); } else { - if (lp_client_lanman_auth()) { + if (use_lanman) { bool ok; lm = data_blob(NULL, 24); - ok = SMBencrypt(pass, params.password.response.challenge, + ok = SMBencrypt(pass, + params.password.response.challenge, lm.data); if (!ok) { data_blob_free(&lm); @@ -1368,7 +1514,8 @@ static bool wbinfo_auth_crap(char *username) WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed"); if (wbc_status == WBC_ERR_AUTH_ERROR) { - d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", + d_fprintf(stderr, + "error code was %s (0x%x)\nerror messsage was: %s\n", err->nt_string, err->nt_status, err->display_string); @@ -1379,11 +1526,48 @@ static bool wbinfo_auth_crap(char *username) data_blob_free(&nt); data_blob_free(&lm); - SAFE_FREE(pass); return WBC_ERROR_IS_OK(wbc_status); } +/* Save creds with winbind */ + +static bool wbinfo_ccache_save(char *username) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + char *s = NULL; + char *p = NULL; + char *password = NULL; + char *name = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + s = talloc_strdup(frame, username); + if (s == NULL) { + return false; + } + + p = strchr(s, '%'); + if (p != NULL) { + *p = 0; + p++; + password = talloc_strdup(frame, p); + } else { + password = wbinfo_prompt_pass(frame, NULL, username); + } + + name = s; + + wbc_status = wbcCredentialSave(name, password); + + d_printf("saving creds %s\n", + WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed"); + + TALLOC_FREE(frame); + + return WBC_ERROR_IS_OK(wbc_status); +} + +#ifdef WITH_FAKE_KASERVER /* Authenticate a user with a plaintext password and set a token */ static bool wbinfo_klog(char *username) @@ -1412,7 +1596,8 @@ static bool wbinfo_klog(char *username) request.flags |= WBFLAG_PAM_AFS_TOKEN; - result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response); + result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, + &response); /* Display response */ @@ -1420,7 +1605,8 @@ static bool wbinfo_klog(char *username) (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed"); if (response.data.auth.nt_status) - d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", + d_fprintf(stderr, + "error code was %s (0x%x)\nerror messsage was: %s\n", response.data.auth.nt_status_string, response.data.auth.nt_status, response.data.auth.error_string); @@ -1441,6 +1627,13 @@ static bool wbinfo_klog(char *username) d_printf("Successfully created AFS token\n"); return true; } +#else +static bool wbinfo_klog(char *username) +{ + d_fprintf(stderr, "No AFS support compiled in.\n"); + return false; +} +#endif /* Print domain users */ @@ -1506,92 +1699,15 @@ static bool print_domain_groups(const char *domain) static bool wbinfo_set_auth_user(char *username) { - const char *password; - char *p; - fstring user, domain; - - /* Separate into user and password */ - - parse_wbinfo_domain_user(username, domain, user); - - p = strchr(user, '%'); - - if (p != NULL) { - *p = 0; - password = p+1; - } else { - char *thepass = getpass("Password: "); - if (thepass) { - password = thepass; - } else - password = ""; - } - - /* Store or remove DOMAIN\username%password in secrets.tdb */ - - secrets_init(); - - if (user[0]) { - - if (!secrets_store(SECRETS_AUTH_USER, user, - strlen(user) + 1)) { - d_fprintf(stderr, "error storing username\n"); - return false; - } - - /* We always have a domain name added by the - parse_wbinfo_domain_user() function. */ - - if (!secrets_store(SECRETS_AUTH_DOMAIN, domain, - strlen(domain) + 1)) { - d_fprintf(stderr, "error storing domain name\n"); - return false; - } - - } else { - secrets_delete(SECRETS_AUTH_USER); - secrets_delete(SECRETS_AUTH_DOMAIN); - } - - if (password[0]) { - - if (!secrets_store(SECRETS_AUTH_PASSWORD, password, - strlen(password) + 1)) { - d_fprintf(stderr, "error storing password\n"); - return false; - } - - } else - secrets_delete(SECRETS_AUTH_PASSWORD); - - return true; + d_fprintf(stderr, "This functionality was moved to the 'net' utility.\n" + "See 'net help setauthuser' for details.\n"); + return false; } static void wbinfo_get_auth_user(void) { - char *user, *domain, *password; - - /* Lift data from secrets file */ - - secrets_fetch_ipc_userpass(&user, &domain, &password); - - if ((!user || !*user) && (!domain || !*domain ) && (!password || !*password)){ - - SAFE_FREE(user); - SAFE_FREE(domain); - SAFE_FREE(password); - d_printf("No authorised user configured\n"); - return; - } - - /* Pretty print authorised user info */ - - d_printf("%s%s%s%s%s\n", domain ? domain : "", domain ? lp_winbind_separator(): "", - user, password ? "%" : "", password ? password : ""); - - SAFE_FREE(user); - SAFE_FREE(domain); - SAFE_FREE(password); + d_fprintf(stderr, "This functionality was moved to the 'net' utility.\n" + "See 'net help getauthuser' for details.\n"); } static bool wbinfo_ping(void) @@ -1613,20 +1729,18 @@ static bool wbinfo_change_user_password(const char *username) wbcErr wbc_status; char *old_password = NULL; char *new_password = NULL; + TALLOC_CTX *frame = talloc_tos(); - old_password = wbinfo_prompt_pass("old", username); - new_password = wbinfo_prompt_pass("new", username); + old_password = wbinfo_prompt_pass(frame, "old", username); + new_password = wbinfo_prompt_pass(frame, "new", username); - wbc_status = wbcChangeUserPassword(username, old_password, new_password); + wbc_status = wbcChangeUserPassword(username, old_password,new_password); /* Display response */ d_printf("Password change for user %s %s\n", username, WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed"); - SAFE_FREE(old_password); - SAFE_FREE(new_password); - return WBC_ERROR_IS_OK(wbc_status); } @@ -1658,7 +1772,11 @@ enum { OPT_VERBOSE, OPT_ONLINESTATUS, OPT_CHANGE_USER_PASSWORD, - OPT_SID_TO_FULLNAME + OPT_PING_DC, + OPT_CCACHE_SAVE, + OPT_SID_TO_FULLNAME, + OPT_NTLMV2, + OPT_LANMAN }; int main(int argc, char **argv, char **envp) @@ -1673,6 +1791,8 @@ int main(int argc, char **argv, char **envp) int int_subarg = -1; int result = 1; bool verbose = false; + bool use_ntlmv2 = false; + bool use_lanman = false; struct poptOption long_options[] = { POPT_AUTOHELP @@ -1702,6 +1822,9 @@ int main(int argc, char **argv, char **envp) { "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" }, { "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, + "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" }, @@ -1720,6 +1843,9 @@ int main(int argc, char **argv, char **envp) { "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" }, { "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 " + "operation", "user%password" }, { "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" }, @@ -1737,7 +1863,8 @@ int main(int argc, char **argv, char **envp) { "separator", 0, POPT_ARG_NONE, 0, OPT_SEPARATOR, "Get the active winbind separator", NULL }, { "verbose", 0, POPT_ARG_NONE, 0, OPT_VERBOSE, "Print additional information per command", NULL }, { "change-user-password", 0, POPT_ARG_STRING, &string_arg, OPT_CHANGE_USER_PASSWORD, "Change the password for a user", NULL }, - POPT_COMMON_CONFIGFILE + { "ntlmv2", 0, POPT_ARG_NONE, 0, OPT_NTLMV2, "Use NTLMv2 cryptography for user authentication", NULL}, + { "lanman", 0, POPT_ARG_NONE, 0, OPT_LANMAN, "Use lanman cryptography for user authentication", NULL}, POPT_COMMON_VERSION POPT_TABLEEND }; @@ -1748,7 +1875,8 @@ int main(int argc, char **argv, char **envp) /* Parse options */ - pc = poptGetContext("wbinfo", argc, (const char **)argv, long_options, 0); + pc = poptGetContext("wbinfo", argc, (const char **)argv, + long_options, 0); /* Parse command line options */ @@ -1761,24 +1889,19 @@ int main(int argc, char **argv, char **envp) /* get the generic configuration parameters like --domain */ switch (opt) { case OPT_VERBOSE: - verbose = True; + verbose = true; + break; + case OPT_NTLMV2: + use_ntlmv2 = true; + break; + case OPT_LANMAN: + use_lanman = true; break; } } poptFreeContext(pc); - if (!lp_load(get_dyn_CONFIGFILE(), true, false, false, true)) { - d_fprintf(stderr, "wbinfo: error opening config file %s. Error was %s\n", - get_dyn_CONFIGFILE(), strerror(errno)); - exit(1); - } - - if (!init_names()) - return 1; - - load_interfaces(); - pc = poptGetContext(NULL, argc, (const char **)argv, long_options, POPT_CONTEXT_KEEP_FIRST); @@ -1786,19 +1909,23 @@ int main(int argc, char **argv, char **envp) switch (opt) { case 'u': if (!print_domain_users(opt_domain_name)) { - d_fprintf(stderr, "Error looking up domain users\n"); + d_fprintf(stderr, + "Error looking up domain users\n"); goto done; } break; case 'g': if (!print_domain_groups(opt_domain_name)) { - d_fprintf(stderr, "Error looking up domain groups\n"); + d_fprintf(stderr, + "Error looking up domain groups\n"); goto done; } break; case 's': if (!wbinfo_lookupsid(string_arg)) { - d_fprintf(stderr, "Could not lookup sid %s\n", string_arg); + d_fprintf(stderr, + "Could not lookup sid %s\n", + string_arg); goto done; } break; @@ -1811,52 +1938,63 @@ int main(int argc, char **argv, char **envp) break; case 'R': if (!wbinfo_lookuprids(opt_domain_name, string_arg)) { - d_fprintf(stderr, "Could not lookup RIDs %s\n", string_arg); + d_fprintf(stderr, "Could not lookup RIDs %s\n", + string_arg); goto done; } break; case 'n': if (!wbinfo_lookupname(string_arg)) { - d_fprintf(stderr, "Could not lookup name %s\n", string_arg); + d_fprintf(stderr, "Could not lookup name %s\n", + string_arg); goto done; } break; case 'N': if (!wbinfo_wins_byname(string_arg)) { - d_fprintf(stderr, "Could not lookup WINS by name %s\n", string_arg); + d_fprintf(stderr, + "Could not lookup WINS by name %s\n", + string_arg); goto done; } break; case 'I': if (!wbinfo_wins_byip(string_arg)) { - d_fprintf(stderr, "Could not lookup WINS by IP %s\n", string_arg); + d_fprintf(stderr, + "Could not lookup WINS by IP %s\n", + string_arg); goto done; } break; case 'U': if (!wbinfo_uid_to_sid(int_arg)) { - d_fprintf(stderr, "Could not convert uid %d to sid\n", int_arg); + d_fprintf(stderr, + "Could not convert uid %d to sid\n", + int_arg); goto done; } break; case 'G': if (!wbinfo_gid_to_sid(int_arg)) { - d_fprintf(stderr, "Could not convert gid %d to sid\n", - int_arg); + d_fprintf(stderr, + "Could not convert gid %d to sid\n", + int_arg); goto done; } break; case 'S': if (!wbinfo_sid_to_uid(string_arg)) { - d_fprintf(stderr, "Could not convert sid %s to uid\n", - string_arg); + d_fprintf(stderr, + "Could not convert sid %s to uid\n", + string_arg); goto done; } break; case 'Y': if (!wbinfo_sid_to_gid(string_arg)) { - d_fprintf(stderr, "Could not convert sid %s to gid\n", - string_arg); + d_fprintf(stderr, + "Could not convert sid %s to gid\n", + string_arg); goto done; } break; @@ -1915,46 +2053,64 @@ int main(int argc, char **argv, char **envp) } break; case 't': - if (!wbinfo_check_secret()) { + if (!wbinfo_check_secret(opt_domain_name)) { d_fprintf(stderr, "Could not check secret\n"); goto done; } break; + case 'c': + if (!wbinfo_change_secret(opt_domain_name)) { + d_fprintf(stderr, "Could not change secret\n"); + goto done; + } + break; + case OPT_PING_DC: + if (!wbinfo_ping_dc()) { + d_fprintf(stderr, "Could not ping our DC\n"); + goto done; + } + break; case 'm': if (!wbinfo_list_domains(false, verbose)) { - d_fprintf(stderr, "Could not list trusted domains\n"); + d_fprintf(stderr, + "Could not list trusted domains\n"); goto done; } break; case OPT_SEQUENCE: if (!wbinfo_show_sequence(opt_domain_name)) { - d_fprintf(stderr, "Could not show sequence numbers\n"); + d_fprintf(stderr, + "Could not show sequence numbers\n"); goto done; } break; case OPT_ONLINESTATUS: if (!wbinfo_show_onlinestatus(opt_domain_name)) { - d_fprintf(stderr, "Could not show online-status\n"); + d_fprintf(stderr, + "Could not show online-status\n"); goto done; } break; case 'D': if (!wbinfo_domain_info(string_arg)) { - d_fprintf(stderr, "Could not get domain info\n"); + d_fprintf(stderr, + "Could not get domain info\n"); goto done; } break; case 'i': if (!wbinfo_get_userinfo(string_arg)) { - d_fprintf(stderr, "Could not get info for user %s\n", - string_arg); + d_fprintf(stderr, + "Could not get info for user %s\n", + string_arg); goto done; } break; case OPT_USER_SIDINFO: if ( !wbinfo_get_user_sidinfo(string_arg)) { - d_fprintf(stderr, "Could not get info for user sid %s\n", - string_arg); + d_fprintf(stderr, + "Could not get info for user " + "sid %s\n", string_arg); goto done; } break; @@ -1981,27 +2137,31 @@ int main(int argc, char **argv, char **envp) break; case 'r': if (!wbinfo_get_usergroups(string_arg)) { - d_fprintf(stderr, "Could not get groups for user %s\n", - string_arg); + d_fprintf(stderr, + "Could not get groups for user %s\n", + string_arg); goto done; } break; case OPT_USERSIDS: if (!wbinfo_get_usersids(string_arg)) { - d_fprintf(stderr, "Could not get group SIDs for user SID %s\n", - string_arg); + d_fprintf(stderr, "Could not get group SIDs " + "for user SID %s\n", + string_arg); goto done; } break; case OPT_USERDOMGROUPS: if (!wbinfo_get_userdomgroups(string_arg)) { - d_fprintf(stderr, "Could not get user's domain groups " - "for user SID %s\n", string_arg); + d_fprintf(stderr, "Could not get user's domain " + "groups for user SID %s\n", + string_arg); goto done; } break; case OPT_SIDALIASES: - if (!wbinfo_get_sidaliases(opt_domain_name, string_arg)) { + if (!wbinfo_get_sidaliases(opt_domain_name, + string_arg)) { d_fprintf(stderr, "Could not get sid aliases " "for user SID %s\n", string_arg); goto done; @@ -2011,14 +2171,19 @@ int main(int argc, char **argv, char **envp) bool got_error = false; if (!wbinfo_auth(string_arg)) { - d_fprintf(stderr, "Could not authenticate user %s with " - "plaintext password\n", string_arg); + d_fprintf(stderr, + "Could not authenticate user " + "%s with plaintext " + "password\n", string_arg); got_error = true; } - if (!wbinfo_auth_crap(string_arg)) { - d_fprintf(stderr, "Could not authenticate user %s with " - "challenge/response\n", string_arg); + if (!wbinfo_auth_crap(string_arg, use_ntlmv2, + use_lanman)) { + d_fprintf(stderr, + "Could not authenticate user " + "%s with challenge/response\n", + string_arg); got_error = true; } @@ -2027,14 +2192,19 @@ int main(int argc, char **argv, char **envp) break; } case 'K': { - uint32 flags = WBFLAG_PAM_KRB5 | - WBFLAG_PAM_CACHED_LOGIN | + uint32_t flags = WBFLAG_PAM_KRB5 | + WBFLAG_PAM_CACHED_LOGIN | WBFLAG_PAM_FALLBACK_AFTER_KRB5 | - WBFLAG_PAM_INFO3_TEXT; - - if (!wbinfo_auth_krb5(string_arg, "FILE", flags)) { - d_fprintf(stderr, "Could not authenticate user [%s] with " - "Kerberos (ccache: %s)\n", string_arg, "FILE"); + WBFLAG_PAM_INFO3_TEXT | + WBFLAG_PAM_CONTACT_TRUSTDOM; + + if (!wbinfo_auth_krb5(string_arg, "FILE", + flags)) { + d_fprintf(stderr, + "Could not authenticate user " + "[%s] with Kerberos " + "(ccache: %s)\n", string_arg, + "FILE"); goto done; } break; @@ -2058,6 +2228,12 @@ int main(int argc, char **argv, char **envp) break; case OPT_GET_AUTH_USER: wbinfo_get_auth_user(); + goto done; + break; + case OPT_CCACHE_SAVE: + if (!wbinfo_ccache_save(string_arg)) { + goto done; + } break; case OPT_GETDCNAME: if (!wbinfo_getdcname(string_arg)) { @@ -2070,7 +2246,7 @@ int main(int argc, char **argv, char **envp) } break; case OPT_SEPARATOR: { - const char sep = winbind_separator_int(true); + const char sep = winbind_separator(); if ( !sep ) { goto done; } @@ -2089,7 +2265,8 @@ int main(int argc, char **argv, char **envp) break; case OPT_CHANGE_USER_PASSWORD: if (!wbinfo_change_user_password(string_arg)) { - d_fprintf(stderr, "Could not change user password " + d_fprintf(stderr, + "Could not change user password " "for user %s\n", string_arg); goto done; } @@ -2100,6 +2277,10 @@ int main(int argc, char **argv, char **envp) break; case OPT_VERBOSE: break; + case OPT_NTLMV2: + break; + case OPT_LANMAN: + break; default: d_fprintf(stderr, "Invalid option\n"); poptPrintHelp(pc, stderr, 0); @@ -2112,7 +2293,7 @@ int main(int argc, char **argv, char **envp) /* Exit code */ done: - talloc_destroy(frame); + talloc_free(frame); poptFreeContext(pc); return result; diff --git a/nsswitch/wbinfo4.c b/nsswitch/wbinfo4.c deleted file mode 100644 index bb6d7a8cf9..0000000000 --- a/nsswitch/wbinfo4.c +++ /dev/null @@ -1,1331 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Winbind status program. - - Copyright (C) Tim Potter 2000-2003 - Copyright (C) Andrew Bartlett 2002-2007 - - 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 - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "includes.h" -#include "winbind_client.h" -#include "librpc/gen_ndr/ndr_netlogon.h" -#include "libcli/auth/libcli_auth.h" -#include "libcli/security/security.h" -#include "lib/cmdline/popt_common.h" -#include "dynconfig/dynconfig.h" -#include "param/param.h" - -#ifndef fstrcpy -#define fstrcpy(d,s) safe_strcpy((d),(s),sizeof(fstring)-1) -#endif - -extern int winbindd_fd; - -static char winbind_separator_int(bool strict) -{ - struct winbindd_response response; - static bool got_sep; - static char sep; - - if (got_sep) - return sep; - - ZERO_STRUCT(response); - - /* Send off request */ - - if (winbindd_request_response(WINBINDD_INFO, NULL, &response) != - NSS_STATUS_SUCCESS) { - d_fprintf(stderr, "could not obtain winbind separator!\n"); - if (strict) { - return 0; - } - /* HACK: (this module should not call lp_ funtions) */ - return *lp_winbind_separator(cmdline_lp_ctx); - } - - sep = response.data.info.winbind_separator; - got_sep = true; - - if (!sep) { - d_fprintf(stderr, "winbind separator was NULL!\n"); - if (strict) { - return 0; - } - /* HACK: (this module should not call lp_ funtions) */ - sep = *lp_winbind_separator(cmdline_lp_ctx); - } - - return sep; -} - -static char winbind_separator(void) -{ - return winbind_separator_int(false); -} - -static const char *get_winbind_domain(void) -{ - struct winbindd_response response; - static fstring winbind_domain; - - ZERO_STRUCT(response); - - /* Send off request */ - - if (winbindd_request_response(WINBINDD_DOMAIN_NAME, NULL, &response) != - NSS_STATUS_SUCCESS) { - d_fprintf(stderr, "could not obtain winbind domain name!\n"); - - /* HACK: (this module should not call lp_ funtions) */ - return lp_workgroup(cmdline_lp_ctx); - } - - fstrcpy(winbind_domain, response.data.domain_name); - - return winbind_domain; - -} - -/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the - form DOMAIN/user into a domain and a user */ - -static bool parse_wbinfo_domain_user(const char *domuser, fstring domain, - fstring user) -{ - - char *p = strchr(domuser,winbind_separator()); - - if (!p) { - fstrcpy(user, domuser); - fstrcpy(domain, get_winbind_domain()); - return true; - } - - fstrcpy(user, p+1); - fstrcpy(domain, domuser); - domain[PTR_DIFF(p, domuser)] = 0; - strupper_m(domain); - - return true; -} - -/* pull pwent info for a given user */ - -static bool wbinfo_get_userinfo(char *user) -{ - struct winbindd_request request; - struct winbindd_response response; - NSS_STATUS result; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Send request */ - - fstrcpy(request.data.username, user); - - result = winbindd_request_response(WINBINDD_GETPWNAM, &request, &response); - - if (result != NSS_STATUS_SUCCESS) - return false; - - d_printf( "%s:%s:%d:%d:%s:%s:%s\n", - response.data.pw.pw_name, - response.data.pw.pw_passwd, - response.data.pw.pw_uid, - response.data.pw.pw_gid, - response.data.pw.pw_gecos, - response.data.pw.pw_dir, - response.data.pw.pw_shell ); - - return true; -} - -/* pull pwent info for a given uid */ -static bool wbinfo_get_uidinfo(int uid) -{ - struct winbindd_request request; - struct winbindd_response response; - NSS_STATUS result; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - request.data.uid = uid; - - result = winbindd_request_response(WINBINDD_GETPWUID, &request, &response); - - if (result != NSS_STATUS_SUCCESS) - return false; - - d_printf( "%s:%s:%d:%d:%s:%s:%s\n", - response.data.pw.pw_name, - response.data.pw.pw_passwd, - response.data.pw.pw_uid, - response.data.pw.pw_gid, - response.data.pw.pw_gecos, - response.data.pw.pw_dir, - response.data.pw.pw_shell ); - - return true; -} - -/* pull grent for a given group */ -static bool wbinfo_get_groupinfo(char *group) -{ - struct winbindd_request request; - struct winbindd_response response; - NSS_STATUS result; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Send request */ - - fstrcpy(request.data.groupname, group); - - result = winbindd_request_response(WINBINDD_GETGRNAM, &request, - &response); - - if ( result != NSS_STATUS_SUCCESS) - return false; - - d_printf( "%s:%s:%d\n", - response.data.gr.gr_name, - response.data.gr.gr_passwd, - response.data.gr.gr_gid ); - - return true; -} - -/* pull grent for a given gid */ -static bool wbinfo_get_gidinfo(int gid) -{ - struct winbindd_request request; - struct winbindd_response response; - NSS_STATUS result; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Send request */ - - request.data.gid = gid; - - result = winbindd_request_response(WINBINDD_GETGRGID, &request, - &response); - - if ( result != NSS_STATUS_SUCCESS) - return false; - - d_printf( "%s:%s:%d\n", - response.data.gr.gr_name, - response.data.gr.gr_passwd, - response.data.gr.gr_gid ); - - return true; -} - -/* List groups a user is a member of */ - -static bool wbinfo_get_usergroups(char *user) -{ - struct winbindd_request request; - struct winbindd_response response; - NSS_STATUS result; - int i; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Send request */ - - fstrcpy(request.data.username, user); - - result = winbindd_request_response(WINBINDD_GETGROUPS, &request, &response); - - if (result != NSS_STATUS_SUCCESS) - return false; - - for (i = 0; i < response.data.num_entries; i++) - d_printf("%d\n", (int)((gid_t *)response.extra_data.data)[i]); - - SAFE_FREE(response.extra_data.data); - - return true; -} - - -/* List group SIDs a user SID is a member of */ -static bool wbinfo_get_usersids(char *user_sid) -{ - struct winbindd_request request; - struct winbindd_response response; - NSS_STATUS result; - int i; - const char *s; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Send request */ - fstrcpy(request.data.sid, user_sid); - - result = winbindd_request_response(WINBINDD_GETUSERSIDS, &request, &response); - - if (result != NSS_STATUS_SUCCESS) - return false; - - s = (const char *)response.extra_data.data; - for (i = 0; i < response.data.num_entries; i++) { - d_printf("%s\n", s); - s += strlen(s) + 1; - } - - SAFE_FREE(response.extra_data.data); - - return true; -} - -static bool wbinfo_get_userdomgroups(const char *user_sid) -{ - struct winbindd_request request; - struct winbindd_response response; - NSS_STATUS result; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Send request */ - fstrcpy(request.data.sid, user_sid); - - result = winbindd_request_response(WINBINDD_GETUSERDOMGROUPS, &request, - &response); - - if (result != NSS_STATUS_SUCCESS) - return false; - - if (response.data.num_entries != 0) - printf("%s", (char *)response.extra_data.data); - - SAFE_FREE(response.extra_data.data); - - return true; -} - -/* Convert NetBIOS name to IP */ - -static bool wbinfo_wins_byname(char *name) -{ - struct winbindd_request request; - struct winbindd_response response; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Send request */ - - fstrcpy(request.data.winsreq, name); - - if (winbindd_request_response(WINBINDD_WINS_BYNAME, &request, &response) != - NSS_STATUS_SUCCESS) { - return false; - } - - /* Display response */ - - d_printf("%s\n", response.data.winsresp); - - return true; -} - -/* Convert IP to NetBIOS name */ - -static bool wbinfo_wins_byip(char *ip) -{ - struct winbindd_request request; - struct winbindd_response response; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Send request */ - - fstrcpy(request.data.winsreq, ip); - - if (winbindd_request_response(WINBINDD_WINS_BYIP, &request, &response) != - NSS_STATUS_SUCCESS) { - return false; - } - - /* Display response */ - - d_printf("%s\n", response.data.winsresp); - - return true; -} - -/* List trusted domains */ - -static bool wbinfo_list_domains(bool list_all_domains) -{ - struct winbindd_request request; - struct winbindd_response response; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Send request */ - - request.data.list_all_domains = list_all_domains; - - if (winbindd_request_response(WINBINDD_LIST_TRUSTDOM, &request, &response) != - NSS_STATUS_SUCCESS) - return false; - - /* Display response */ - - if (response.extra_data.data) { - const char *extra_data = (char *)response.extra_data.data; - fstring name; - char *p; - - while(next_token(&extra_data, name, "\n", sizeof(fstring))) { - p = strchr(name, '\\'); - if (p == 0) { - d_fprintf(stderr, "Got invalid response: %s\n", - extra_data); - return false; - } - *p = 0; - d_printf("%s\n", name); - } - - SAFE_FREE(response.extra_data.data); - } - - return true; -} - -/* List own domain */ - -static bool wbinfo_list_own_domain(void) -{ - d_printf("%s\n", get_winbind_domain()); - - return true; -} - -/* show sequence numbers */ -static bool wbinfo_show_sequence(const char *domain) -{ - struct winbindd_request request; - struct winbindd_response response; - - ZERO_STRUCT(response); - ZERO_STRUCT(request); - - if ( domain ) - fstrcpy( request.domain_name, domain ); - - /* Send request */ - - if (winbindd_request_response(WINBINDD_SHOW_SEQUENCE, &request, &response) != - NSS_STATUS_SUCCESS) - return false; - - /* Display response */ - - if (response.extra_data.data) { - char *extra_data = (char *)response.extra_data.data; - d_printf("%s", extra_data); - SAFE_FREE(response.extra_data.data); - } - - return true; -} - -/* Show domain info */ - -static bool wbinfo_domain_info(const char *domain_name) -{ - struct winbindd_request request; - struct winbindd_response response; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - if ((strequal(domain_name, ".")) || (domain_name[0] == '\0')) - fstrcpy(request.domain_name, get_winbind_domain()); - else - fstrcpy(request.domain_name, domain_name); - - /* Send request */ - - if (winbindd_request_response(WINBINDD_DOMAIN_INFO, &request, &response) != - NSS_STATUS_SUCCESS) - return false; - - /* Display response */ - - d_printf("Name : %s\n", response.data.domain_info.name); - d_printf("Alt_Name : %s\n", response.data.domain_info.alt_name); - - d_printf("SID : %s\n", response.data.domain_info.sid); - - d_printf("Active Directory : %s\n", - response.data.domain_info.active_directory ? "Yes" : "No"); - d_printf("Native : %s\n", - response.data.domain_info.native_mode ? "Yes" : "No"); - - d_printf("Primary : %s\n", - response.data.domain_info.primary ? "Yes" : "No"); - - return true; -} - -/* Get a foreign DC's name */ -static bool wbinfo_getdcname(const char *domain_name) -{ - struct winbindd_request request; - struct winbindd_response response; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - fstrcpy(request.domain_name, domain_name); - - /* Send request */ - - if (winbindd_request_response(WINBINDD_GETDCNAME, &request, &response) != - NSS_STATUS_SUCCESS) { - d_fprintf(stderr, "Could not get dc name for %s\n", domain_name); - return false; - } - - /* Display response */ - - d_printf("%s\n", response.data.dc_name); - - return true; -} - -/* Check trust account password */ - -static bool wbinfo_check_secret(void) -{ - struct winbindd_response response; - NSS_STATUS result; - - ZERO_STRUCT(response); - - result = winbindd_request_response(WINBINDD_CHECK_MACHACC, NULL, &response); - - d_printf("checking the trust secret via RPC calls %s\n", - (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed"); - - if (result != NSS_STATUS_SUCCESS) - d_fprintf(stderr, "error code was %s (0x%x)\n", - response.data.auth.nt_status_string, - response.data.auth.nt_status); - - return result == NSS_STATUS_SUCCESS; -} - -/* Convert uid to sid */ - -static bool wbinfo_uid_to_sid(uid_t uid) -{ - struct winbindd_request request; - struct winbindd_response response; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Send request */ - - request.data.uid = uid; - - if (winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response) != - NSS_STATUS_SUCCESS) - return false; - - /* Display response */ - - d_printf("%s\n", response.data.sid.sid); - - return true; -} - -/* Convert gid to sid */ - -static bool wbinfo_gid_to_sid(gid_t gid) -{ - struct winbindd_request request; - struct winbindd_response response; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Send request */ - - request.data.gid = gid; - - if (winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response) != - NSS_STATUS_SUCCESS) - return false; - - /* Display response */ - - d_printf("%s\n", response.data.sid.sid); - - return true; -} - -/* Convert sid to uid */ - -static bool wbinfo_sid_to_uid(char *sid) -{ - struct winbindd_request request; - struct winbindd_response response; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Send request */ - - fstrcpy(request.data.sid, sid); - - if (winbindd_request_response(WINBINDD_SID_TO_UID, &request, &response) != - NSS_STATUS_SUCCESS) - return false; - - /* Display response */ - - d_printf("%d\n", (int)response.data.uid); - - return true; -} - -static bool wbinfo_sid_to_gid(char *sid) -{ - struct winbindd_request request; - struct winbindd_response response; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Send request */ - - fstrcpy(request.data.sid, sid); - - if (winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response) != - NSS_STATUS_SUCCESS) - return false; - - /* Display response */ - - d_printf("%d\n", (int)response.data.gid); - - return true; -} - -static const char *sid_type_lookup(enum lsa_SidType r) -{ - switch (r) { - case SID_NAME_USE_NONE: return "SID_NAME_USE_NONE"; break; - case SID_NAME_USER: return "SID_NAME_USER"; break; - case SID_NAME_DOM_GRP: return "SID_NAME_DOM_GRP"; break; - case SID_NAME_DOMAIN: return "SID_NAME_DOMAIN"; break; - case SID_NAME_ALIAS: return "SID_NAME_ALIAS"; break; - case SID_NAME_WKN_GRP: return "SID_NAME_WKN_GRP"; break; - case SID_NAME_DELETED: return "SID_NAME_DELETED"; break; - case SID_NAME_INVALID: return "SID_NAME_INVALID"; break; - case SID_NAME_UNKNOWN: return "SID_NAME_UNKNOWN"; break; - case SID_NAME_COMPUTER: return "SID_NAME_COMPUTER"; break; - } - return "Invalid sid type\n"; -} - -/* Convert sid to string */ - -static bool wbinfo_lookupsid(char *sid) -{ - struct winbindd_request request; - struct winbindd_response response; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - /* Send off request */ - - fstrcpy(request.data.sid, sid); - - if (winbindd_request_response(WINBINDD_LOOKUPSID, &request, &response) != - NSS_STATUS_SUCCESS) - return false; - - /* Display response */ - - d_printf("%s%c%s %s\n", response.data.name.dom_name, - winbind_separator(), response.data.name.name, - sid_type_lookup(response.data.name.type)); - - return true; -} - -/* Convert string to sid */ - -static bool wbinfo_lookupname(char *name) -{ - struct winbindd_request request; - struct winbindd_response response; - - /* Send off request */ - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - parse_wbinfo_domain_user(name, request.data.name.dom_name, - request.data.name.name); - - if (winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response) != - NSS_STATUS_SUCCESS) - return false; - - /* Display response */ - - d_printf("%s %s (%d)\n", response.data.sid.sid, sid_type_lookup(response.data.sid.type), response.data.sid.type); - - return true; -} - -/* Authenticate a user with a plaintext password */ - -static bool wbinfo_auth_krb5(char *username, const char *cctype, uint32_t flags) -{ - struct winbindd_request request; - struct winbindd_response response; - NSS_STATUS result; - char *p; - - /* Send off request */ - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - p = strchr(username, '%'); - - if (p) { - *p = 0; - fstrcpy(request.data.auth.user, username); - fstrcpy(request.data.auth.pass, p + 1); - *p = '%'; - } else - fstrcpy(request.data.auth.user, username); - - request.flags = flags; - - fstrcpy(request.data.auth.krb5_cc_type, cctype); - - request.data.auth.uid = geteuid(); - - result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response); - - /* Display response */ - - d_printf("plaintext kerberos password authentication for [%s] %s (requesting cctype: %s)\n", - username, (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed", cctype); - - if (response.data.auth.nt_status) - d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", - response.data.auth.nt_status_string, - response.data.auth.nt_status, - response.data.auth.error_string); - - if (result == NSS_STATUS_SUCCESS) { - - if (request.flags & WBFLAG_PAM_INFO3_TEXT) { - if (response.data.auth.info3.user_flgs & NETLOGON_CACHED_ACCOUNT) { - d_printf("user_flgs: NETLOGON_CACHED_ACCOUNT\n"); - } - } - - if (response.data.auth.krb5ccname[0] != '\0') { - d_printf("credentials were put in: %s\n", response.data.auth.krb5ccname); - } else { - d_printf("no credentials cached\n"); - } - } - - return result == NSS_STATUS_SUCCESS; -} - -/* Authenticate a user with a plaintext password */ - -static bool wbinfo_auth(char *username) -{ - struct winbindd_request request; - struct winbindd_response response; - NSS_STATUS result; - char *p; - - /* Send off request */ - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - p = strchr(username, '%'); - - if (p) { - *p = 0; - fstrcpy(request.data.auth.user, username); - fstrcpy(request.data.auth.pass, p + 1); - *p = '%'; - } else - fstrcpy(request.data.auth.user, username); - - result = winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response); - - /* Display response */ - - d_printf("plaintext password authentication %s\n", - (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed"); - - if (response.data.auth.nt_status) - d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", - response.data.auth.nt_status_string, - response.data.auth.nt_status, - response.data.auth.error_string); - - return result == NSS_STATUS_SUCCESS; -} - -/* Authenticate a user with a challenge/response */ - -static bool wbinfo_auth_crap(struct loadparm_context *lp_ctx, char *username) -{ - struct winbindd_request request; - struct winbindd_response response; - NSS_STATUS result; - fstring name_user; - fstring name_domain; - fstring pass; - char *p; - - /* Send off request */ - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - p = strchr(username, '%'); - - if (p) { - *p = 0; - fstrcpy(pass, p + 1); - } - - parse_wbinfo_domain_user(username, name_domain, name_user); - - request.data.auth_crap.logon_parameters = MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT | MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT; - - fstrcpy(request.data.auth_crap.user, name_user); - - fstrcpy(request.data.auth_crap.domain, - name_domain); - - generate_random_buffer(request.data.auth_crap.chal, 8); - - if (lp_client_ntlmv2_auth(lp_ctx)) { - DATA_BLOB server_chal; - DATA_BLOB names_blob; - - DATA_BLOB lm_response; - DATA_BLOB nt_response; - - TALLOC_CTX *mem_ctx; - mem_ctx = talloc_new(NULL); - if (mem_ctx == NULL) { - d_printf("talloc_new failed\n"); - return false; - } - - server_chal = data_blob(request.data.auth_crap.chal, 8); - - /* Pretend this is a login to 'us', for blob purposes */ - names_blob = NTLMv2_generate_names_blob(mem_ctx, lp_netbios_name(lp_ctx), lp_workgroup(lp_ctx)); - - if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain, pass, &server_chal, - &names_blob, - &lm_response, &nt_response, NULL, NULL)) { - data_blob_free(&names_blob); - data_blob_free(&server_chal); - return false; - } - data_blob_free(&names_blob); - data_blob_free(&server_chal); - - memcpy(request.data.auth_crap.nt_resp, nt_response.data, - MIN(nt_response.length, - sizeof(request.data.auth_crap.nt_resp))); - request.data.auth_crap.nt_resp_len = nt_response.length; - - memcpy(request.data.auth_crap.lm_resp, lm_response.data, - MIN(lm_response.length, - sizeof(request.data.auth_crap.lm_resp))); - request.data.auth_crap.lm_resp_len = lm_response.length; - - data_blob_free(&nt_response); - data_blob_free(&lm_response); - - } else { - if (lp_client_lanman_auth(lp_ctx) - && SMBencrypt(pass, request.data.auth_crap.chal, - (unsigned char *)request.data.auth_crap.lm_resp)) { - request.data.auth_crap.lm_resp_len = 24; - } else { - request.data.auth_crap.lm_resp_len = 0; - } - SMBNTencrypt(pass, request.data.auth_crap.chal, - (unsigned char *)request.data.auth_crap.nt_resp); - - request.data.auth_crap.nt_resp_len = 24; - } - - result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response); - - /* Display response */ - - d_printf("challenge/response password authentication %s\n", - (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed"); - - if (response.data.auth.nt_status) - d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", - response.data.auth.nt_status_string, - response.data.auth.nt_status, - response.data.auth.error_string); - - return result == NSS_STATUS_SUCCESS; -} - -/* Print domain users */ - -static bool print_domain_users(const char *domain) -{ - struct winbindd_request request; - struct winbindd_response response; - const char *extra_data; - fstring name; - - /* Send request to winbind daemon */ - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - if (domain) { - /* '.' is the special sign for our own domain */ - if ( strequal(domain, ".") ) - fstrcpy( request.domain_name, get_winbind_domain() ); - else - fstrcpy( request.domain_name, domain ); - } - - if (winbindd_request_response(WINBINDD_LIST_USERS, &request, &response) != - NSS_STATUS_SUCCESS) - return false; - - /* Look through extra data */ - - if (!response.extra_data.data) - return false; - - extra_data = (const char *)response.extra_data.data; - - while(next_token(&extra_data, name, ",", sizeof(fstring))) - d_printf("%s\n", name); - - SAFE_FREE(response.extra_data.data); - - return true; -} - -/* Print domain groups */ - -static bool print_domain_groups(const char *domain) -{ - struct winbindd_request request; - struct winbindd_response response; - const char *extra_data; - fstring name; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - - if (domain) { - if ( strequal(domain, ".") ) - fstrcpy( request.domain_name, get_winbind_domain() ); - else - fstrcpy( request.domain_name, domain ); - } - - if (winbindd_request_response(WINBINDD_LIST_GROUPS, &request, &response) != - NSS_STATUS_SUCCESS) - return false; - - /* Look through extra data */ - - if (!response.extra_data.data) - return false; - - extra_data = (const char *)response.extra_data.data; - - while(next_token(&extra_data, name, ",", sizeof(fstring))) - d_printf("%s\n", name); - - SAFE_FREE(response.extra_data.data); - - return true; -} - -static bool wbinfo_ping(void) -{ - NSS_STATUS result; - - result = winbindd_request_response(WINBINDD_PING, NULL, NULL); - - /* Display response */ - - d_printf("Ping to winbindd %s on fd %d\n", - (result == NSS_STATUS_SUCCESS) ? "succeeded" : "failed", winbindd_fd); - - return result == NSS_STATUS_SUCCESS; -} - -/* Main program */ - -enum { - OPT_SET_AUTH_USER = 1000, - OPT_GET_AUTH_USER, - OPT_DOMAIN_NAME, - OPT_SEQUENCE, - OPT_GETDCNAME, - OPT_USERDOMGROUPS, - OPT_USERSIDS, - OPT_ALLOCATE_UID, - OPT_ALLOCATE_GID, - OPT_SEPARATOR, - OPT_LIST_ALL_DOMAINS, - OPT_LIST_OWN_DOMAIN, - OPT_UID_INFO, - OPT_GROUP_INFO, - OPT_GID_INFO, -}; - -int main(int argc, char **argv, char **envp) -{ - int opt; - - poptContext pc; - static char *string_arg; - static char *opt_domain_name; - static int int_arg; - int result = 1; - - struct poptOption long_options[] = { - POPT_AUTOHELP - - /* longName, shortName, argInfo, argPtr, value, descrip, - argDesc */ - - { "domain-users", 'u', POPT_ARG_NONE, 0, 'u', "Lists all domain users", "domain"}, - { "domain-groups", 'g', POPT_ARG_NONE, 0, 'g', "Lists all domain groups", "domain" }, - { "WINS-by-name", 'N', POPT_ARG_STRING, &string_arg, 'N', "Converts NetBIOS name to IP", "NETBIOS-NAME" }, - { "WINS-by-ip", 'I', POPT_ARG_STRING, &string_arg, 'I', "Converts IP address to NetBIOS name", "IP" }, - { "name-to-sid", 'n', POPT_ARG_STRING, &string_arg, 'n', "Converts name to sid", "NAME" }, - { "sid-to-name", 's', POPT_ARG_STRING, &string_arg, 's', "Converts sid to name", "SID" }, - { "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" }, - { "sid-to-gid", 'Y', POPT_ARG_STRING, &string_arg, 'Y', "Converts sid to gid", "SID" }, - { "check-secret", 't', POPT_ARG_NONE, 0, 't', "Check shared secret" }, - { "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" }, - { "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" }, - { "uid-info", 0, POPT_ARG_INT, &int_arg, OPT_UID_INFO, "Get user info from uid", "UID" }, - { "group-info", 0, POPT_ARG_STRING, &string_arg, OPT_GROUP_INFO, "Get group info", "GROUP" }, - { "gid-info", 0, POPT_ARG_INT, &int_arg, OPT_GID_INFO, "Get group info from gid", "GID" }, - { "user-groups", 'r', POPT_ARG_STRING, &string_arg, 'r', "Get user groups", "USER" }, - { "user-domgroups", 0, POPT_ARG_STRING, &string_arg, - OPT_USERDOMGROUPS, "Get user domain groups", "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" }, - { "getdcname", 0, POPT_ARG_STRING, &string_arg, OPT_GETDCNAME, - "Get a DC name for a foreign domain", "domainname" }, - { "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" }, -#ifdef HAVE_KRB5 - { "krb5auth", 'K', POPT_ARG_STRING, &string_arg, 'K', "authenticate user using Kerberos", "user%password" }, - /* destroys wbinfo --help output */ - /* "user%password,DOM\\user%password,user@EXAMPLE.COM,EXAMPLE.COM\\user%password" }, */ -#endif - { "separator", 0, POPT_ARG_NONE, 0, OPT_SEPARATOR, "Get the active winbind separator", NULL }, - POPT_COMMON_VERSION - POPT_COMMON_SAMBA - POPT_TABLEEND - }; - - /* Parse options */ - - pc = poptGetContext("wbinfo", argc, (const char **)argv, long_options, 0); - - /* Parse command line options */ - - if (argc == 1) { - poptPrintHelp(pc, stderr, 0); - return 1; - } - - while((opt = poptGetNextOpt(pc)) != -1) { - /* get the generic configuration parameters like --domain */ - } - - poptFreeContext(pc); - - pc = poptGetContext(NULL, argc, (const char **)argv, long_options, - POPT_CONTEXT_KEEP_FIRST); - - while((opt = poptGetNextOpt(pc)) != -1) { - switch (opt) { - case 'u': - if (!print_domain_users(opt_domain_name)) { - d_fprintf(stderr, "Error looking up domain users\n"); - goto done; - } - break; - case 'g': - if (!print_domain_groups(opt_domain_name)) { - d_fprintf(stderr, "Error looking up domain groups\n"); - goto done; - } - break; - case 's': - if (!wbinfo_lookupsid(string_arg)) { - d_fprintf(stderr, "Could not lookup sid %s\n", string_arg); - goto done; - } - break; - case 'n': - if (!wbinfo_lookupname(string_arg)) { - d_fprintf(stderr, "Could not lookup name %s\n", string_arg); - goto done; - } - break; - case 'N': - if (!wbinfo_wins_byname(string_arg)) { - d_fprintf(stderr, "Could not lookup WINS by name %s\n", string_arg); - goto done; - } - break; - case 'I': - if (!wbinfo_wins_byip(string_arg)) { - d_fprintf(stderr, "Could not lookup WINS by IP %s\n", string_arg); - goto done; - } - break; - case 'U': - if (!wbinfo_uid_to_sid(int_arg)) { - d_fprintf(stderr, "Could not convert uid %d to sid\n", int_arg); - goto done; - } - break; - case 'G': - if (!wbinfo_gid_to_sid(int_arg)) { - d_fprintf(stderr, "Could not convert gid %d to sid\n", - int_arg); - goto done; - } - break; - case 'S': - if (!wbinfo_sid_to_uid(string_arg)) { - d_fprintf(stderr, "Could not convert sid %s to uid\n", - string_arg); - goto done; - } - break; - case 'Y': - if (!wbinfo_sid_to_gid(string_arg)) { - d_fprintf(stderr, "Could not convert sid %s to gid\n", - string_arg); - goto done; - } - break; - case 't': - if (!wbinfo_check_secret()) { - d_fprintf(stderr, "Could not check secret\n"); - goto done; - } - break; - case 'm': - if (!wbinfo_list_domains(false)) { - d_fprintf(stderr, "Could not list trusted domains\n"); - goto done; - } - break; - case OPT_SEQUENCE: - if (!wbinfo_show_sequence(opt_domain_name)) { - d_fprintf(stderr, "Could not show sequence numbers\n"); - goto done; - } - break; - case 'D': - if (!wbinfo_domain_info(string_arg)) { - d_fprintf(stderr, "Could not get domain info\n"); - goto done; - } - break; - case 'i': - if (!wbinfo_get_userinfo(string_arg)) { - d_fprintf(stderr, "Could not get info for user %s\n", - string_arg); - goto done; - } - break; - case OPT_UID_INFO: - if ( !wbinfo_get_uidinfo(int_arg)) { - d_fprintf(stderr, "Could not get info for uid " - "%d\n", int_arg); - goto done; - } - break; - case OPT_GROUP_INFO: - if ( !wbinfo_get_groupinfo(string_arg)) { - d_fprintf(stderr, "Could not get info for " - "group %s\n", string_arg); - goto done; - } - break; - case OPT_GID_INFO: - if ( !wbinfo_get_gidinfo(int_arg)) { - d_fprintf(stderr, "Could not get info for gid " - "%d\n", int_arg); - goto done; - } - break; - case 'r': - if (!wbinfo_get_usergroups(string_arg)) { - d_fprintf(stderr, "Could not get groups for user %s\n", - string_arg); - goto done; - } - break; - case OPT_USERSIDS: - if (!wbinfo_get_usersids(string_arg)) { - d_fprintf(stderr, "Could not get group SIDs for user SID %s\n", - string_arg); - goto done; - } - break; - case OPT_USERDOMGROUPS: - if (!wbinfo_get_userdomgroups(string_arg)) { - d_fprintf(stderr, "Could not get user's domain groups " - "for user SID %s\n", string_arg); - goto done; - } - break; - case 'a': { - bool got_error = false; - - if (!wbinfo_auth(string_arg)) { - d_fprintf(stderr, "Could not authenticate user %s with " - "plaintext password\n", string_arg); - got_error = true; - } - - if (!wbinfo_auth_crap(cmdline_lp_ctx, string_arg)) { - d_fprintf(stderr, "Could not authenticate user %s with " - "challenge/response\n", string_arg); - got_error = true; - } - - if (got_error) - goto done; - break; - } - case 'K': { - uint32_t flags = WBFLAG_PAM_KRB5 | - WBFLAG_PAM_CACHED_LOGIN | - WBFLAG_PAM_FALLBACK_AFTER_KRB5 | - WBFLAG_PAM_INFO3_TEXT; - - if (!wbinfo_auth_krb5(string_arg, "FILE", flags)) { - d_fprintf(stderr, "Could not authenticate user [%s] with " - "Kerberos (ccache: %s)\n", string_arg, "FILE"); - goto done; - } - break; - } - case 'p': - if (!wbinfo_ping()) { - d_fprintf(stderr, "could not ping winbindd!\n"); - goto done; - } - break; - case OPT_GETDCNAME: - if (!wbinfo_getdcname(string_arg)) { - goto done; - } - break; - case OPT_SEPARATOR: { - const char sep = winbind_separator_int(true); - if ( !sep ) { - goto done; - } - d_printf("%c\n", sep); - break; - } - case OPT_LIST_ALL_DOMAINS: - if (!wbinfo_list_domains(true)) { - goto done; - } - break; - case OPT_LIST_OWN_DOMAIN: - if (!wbinfo_list_own_domain()) { - goto done; - } - break; - /* generic configuration options */ - case OPT_DOMAIN_NAME: - break; - default: - d_fprintf(stderr, "Invalid option\n"); - poptPrintHelp(pc, stderr, 0); - goto done; - } - } - - result = 0; - - /* Exit code */ - - done: - poptFreeContext(pc); - return result; -} diff --git a/nsswitch/winbind_nss_netbsd.c b/nsswitch/winbind_nss_netbsd.c index 9b8e0a2265..f6738061ad 100644 --- a/nsswitch/winbind_nss_netbsd.c +++ b/nsswitch/winbind_nss_netbsd.c @@ -124,7 +124,7 @@ netbsdwinbind_getgrent_r(void *nsrv, void *nscb, va_list ap) *result = NULL; rerrno = 0; - rv = _nss_winbind_getgrent_r(grp, buffer, buflen, rerrno); + rv = _nss_winbind_getgrent_r(grp, buffer, buflen, &rerrno); if (rv == NS_SUCCESS) *result = grp; else @@ -215,7 +215,6 @@ netbsdwinbind_getgroupmembership(void *nsrv, void *nscb, va_list ap) { int *result = va_arg(ap, int *); const char *uname = va_arg(ap, const char *); - gid_t agroup = va_arg(ap, gid_t); gid_t *groups = va_arg(ap, gid_t *); int maxgrp = va_arg(ap, int); int *groupc = va_arg(ap, int *); @@ -312,7 +311,7 @@ netbsdwinbind_getpwent_r(void *nsrv, void *nscb, va_list ap) *result = NULL; rerrno = 0; - rv = _nss_winbind_getpwent_r(pw, buffer, buflen, rerrno); + rv = _nss_winbind_getpwent_r(pw, buffer, buflen, &rerrno); if (rv == NS_SUCCESS) *result = pw; else diff --git a/nsswitch/winbind_struct_protocol.h b/nsswitch/winbind_struct_protocol.h index 11b2069c3a..2e0751f79a 100644 --- a/nsswitch/winbind_struct_protocol.h +++ b/nsswitch/winbind_struct_protocol.h @@ -15,6 +15,11 @@ #define SAFE_FREE(x) do { if(x) {free(x); x=NULL;} } while(0) #endif +#ifndef FSTRING_LEN +#define FSTRING_LEN 256 +typedef char fstring[FSTRING_LEN]; +#endif + #ifndef _WINBINDD_NTDOM_H #define _WINBINDD_NTDOM_H @@ -42,8 +47,11 @@ /* Update this when you change the interface. * 21: added WINBINDD_GETPWSID * added WINBINDD_GETSIDALIASES + * 22: added WINBINDD_PING_DC + * 23: added session_key to ccache_ntlm_auth response + * added WINBINDD_CCACHE_SAVE */ -#define WINBIND_INTERFACE_VERSION 21 +#define WINBIND_INTERFACE_VERSION 23 /* 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 @@ -113,6 +121,8 @@ enum winbindd_cmd { /* Miscellaneous other stuff */ WINBINDD_CHECK_MACHACC, /* Check machine account pw works */ + WINBINDD_CHANGE_MACHACC, /* Change machine account pw */ + WINBINDD_PING_DC, /* Ping the DC through NETLOGON */ WINBINDD_PING, /* Just tell me winbind is running */ WINBINDD_INFO, /* Various bit of info. Currently just tidbits */ WINBINDD_DOMAIN_NAME, /* The domain this winbind server is a member of (lp_workgroup()) */ @@ -164,9 +174,12 @@ enum winbindd_cmd { WINBINDD_DUAL_USERINFO, WINBINDD_DUAL_GETSIDALIASES, + WINBINDD_DUAL_NDRCMD, + /* Complete the challenge phase of the NTLM authentication protocol using cached password. */ WINBINDD_CCACHE_NTLMAUTH, + WINBINDD_CCACHE_SAVE, WINBINDD_NUM_CMDS }; @@ -242,6 +255,7 @@ struct winbindd_request { fstring groupname; /* getgrnam */ uid_t uid; /* getpwuid, uid_to_sid */ gid_t gid; /* getgrgid, gid_to_sid */ + uint32_t ndrcmd; struct { /* We deliberatedly don't split into domain/user to avoid having the client know what the separator @@ -324,6 +338,11 @@ struct winbindd_request { uint32_t challenge_blob_len; } ccache_ntlm_auth; struct { + uid_t uid; + fstring user; + fstring pass; + } ccache_save; + struct { fstring domain_name; fstring domain_guid; fstring site_name; @@ -467,6 +486,7 @@ struct winbindd_response { uint32_t group_rid; } user_info; struct { + uint8_t session_key[16]; uint32_t auth_blob_len; /* blob in extra_data */ } ccache_ntlm_auth; struct { |