From d4db08d7a6e13c87ce6dd09c28917a8bea5a0be6 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 26 Nov 2008 10:18:53 +0000 Subject: [PATCH] * Makefile.in (OBJS): Add setpwd.o. * README: Explain new service to store passwords in the LSA registry area. * bsd_helper.cc (get_token_info): Make externally available. * bsd_helper.h (get_token_info): Declare. * client.cc (client_request::handle_request): Add case for CYGSERVER_REQUEST_SETPWD request. * setpwd.cc: New file implementing the CYGSERVER_REQUEST_SETPWD request. --- winsup/cygserver/ChangeLog | 12 ++++ winsup/cygserver/Makefile.in | 2 +- winsup/cygserver/README | 6 ++ winsup/cygserver/bsd_helper.cc | 2 +- winsup/cygserver/bsd_helper.h | 1 + winsup/cygserver/client.cc | 4 ++ winsup/cygserver/setpwd.cc | 100 +++++++++++++++++++++++++++++++++ 7 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 winsup/cygserver/setpwd.cc diff --git a/winsup/cygserver/ChangeLog b/winsup/cygserver/ChangeLog index c3d4870c1..0ba9e4685 100644 --- a/winsup/cygserver/ChangeLog +++ b/winsup/cygserver/ChangeLog @@ -1,3 +1,15 @@ +2008-11-26 Corinna Vinschen + + * Makefile.in (OBJS): Add setpwd.o. + * README: Explain new service to store passwords in the LSA registry + area. + * bsd_helper.cc (get_token_info): Make externally available. + * bsd_helper.h (get_token_info): Declare. + * client.cc (client_request::handle_request): Add case for + CYGSERVER_REQUEST_SETPWD request. + * setpwd.cc: New file implementing the CYGSERVER_REQUEST_SETPWD + request. + 2008-10-30 Christopher Faylor * Makefile.in: Use -static-libgcc when creating cygserver.exe. diff --git a/winsup/cygserver/Makefile.in b/winsup/cygserver/Makefile.in index dd8ad96d6..4192bda49 100644 --- a/winsup/cygserver/Makefile.in +++ b/winsup/cygserver/Makefile.in @@ -41,7 +41,7 @@ override CXXFLAGS+=-MMD -DHAVE_DECL_GETOPT=0 -D__OUTSIDE_CYGWIN__ -DSYSCONFDIR=" OBJS:= cygserver.o client.o process.o msg.o sem.o shm.o threaded_queue.o \ transport.o transport_pipes.o \ bsd_helper.o bsd_log.o bsd_mutex.o \ - sysv_msg.o sysv_sem.o sysv_shm.o + sysv_msg.o sysv_sem.o sysv_shm.o setpwd.o LIBOBJS:=${patsubst %.o,lib%.o,$(OBJS)} CYGWIN_OBJS:=$(cygwin_build)/version.o diff --git a/winsup/cygserver/README b/winsup/cygserver/README index 279e513eb..01365506f 100644 --- a/winsup/cygserver/README +++ b/winsup/cygserver/README @@ -12,6 +12,12 @@ What is Cygserver? - XSI IPC Message Queues. - XSI IPC Semaphores. - XSI IPC Shared Memory. + - Allows non-privileged users to store obfuscated passwords in the + registry to be used for setuid(2) to create user tokens with network + credentials. This service is used by `passwd -R'. Using the stored + passwords in setuid(2) does not require running cygserver. The + registry storage is the same as Windows uses to store passwords for + accounts running Windows services. Cygserver command line options: diff --git a/winsup/cygserver/bsd_helper.cc b/winsup/cygserver/bsd_helper.cc index a137b7ea6..6dabdc87e 100644 --- a/winsup/cygserver/bsd_helper.cc +++ b/winsup/cygserver/bsd_helper.cc @@ -308,7 +308,7 @@ is_grp_member (gid_t grp, gid_t *grplist, int listsize) * This function mallocs the necessary buffer spcae by itself. It * must be free'd by the calling function. */ -static void * +void * get_token_info (HANDLE tok, TOKEN_INFORMATION_CLASS tic) { void *buf; diff --git a/winsup/cygserver/bsd_helper.h b/winsup/cygserver/bsd_helper.h index 014b82a05..045898573 100644 --- a/winsup/cygserver/bsd_helper.h +++ b/winsup/cygserver/bsd_helper.h @@ -44,6 +44,7 @@ int win_copyout (struct thread *, const void *, void *, size_t); #define copyin(a,b,c) win_copyin((td),(a),(b),(c)) #define copyout(a,b,c) win_copyout((td),(a),(b),(c)) +void *get_token_info (HANDLE, TOKEN_INFORMATION_CLASS); int ipcperm (struct thread *, struct ipc_perm *, unsigned int); int suser (struct thread *); bool adjust_identity_info (struct proc *p); diff --git a/winsup/cygserver/client.cc b/winsup/cygserver/client.cc index 953e5a166..f66a99544 100644 --- a/winsup/cygserver/client.cc +++ b/winsup/cygserver/client.cc @@ -27,6 +27,7 @@ details. */ #include "cygserver_msg.h" #include "cygserver_sem.h" #include "cygserver_shm.h" +#include "cygserver_setpwd.h" #include "cygserver.h" #include "transport.h" @@ -293,6 +294,9 @@ client_request::handle_request (transport_layer_base *const conn, case CYGSERVER_REQUEST_SHM: req = new client_request_shm; break; + case CYGSERVER_REQUEST_SETPWD: + req = new client_request_setpwd; + break; default: syscall_printf ("unknown request code %d received: request ignored", header.request_code); diff --git a/winsup/cygserver/setpwd.cc b/winsup/cygserver/setpwd.cc new file mode 100644 index 000000000..39989f86a --- /dev/null +++ b/winsup/cygserver/setpwd.cc @@ -0,0 +1,100 @@ +/* setpwd.cc: Set LSA private data password for current user. + + Copyright 2008 Red Hat, Inc. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifdef __OUTSIDE_CYGWIN__ +#include "woutsup.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "ntdll.h" + +#include "cygserver.h" +#include "process.h" +#include "transport.h" + +#include "cygserver_setpwd.h" + +client_request_setpwd::client_request_setpwd () + : client_request (CYGSERVER_REQUEST_SETPWD, + &_parameters, sizeof (_parameters)) +{ +} + +void +client_request_setpwd::serve (transport_layer_base *const conn, + process_cache *const cache) +{ + HANDLE tok; + PTOKEN_USER user; + WCHAR sidbuf[128], key_name [128 + wcslen (CYGWIN_LSA_KEY_PREFIX)]; + UNICODE_STRING sid, key, data; + + syscall_printf ("Request to set private data"); + if (msglen () != sizeof (_parameters.in)) + { + syscall_printf ("bad request body length: expecting %lu bytes, got %lu", + sizeof (_parameters), msglen ()); + error_code (EINVAL); + msglen (0); + return; + } + msglen (0); + if (!conn->impersonate_client ()) + { + error_code (EACCES); + return; + } + if (!OpenThreadToken (GetCurrentThread (), TOKEN_READ, TRUE, &tok)) + { + conn->revert_to_self (); + error_code (EACCES); + return; + } + /* Get uid from user SID in token. */ + user = (PTOKEN_USER) get_token_info (tok, TokenUser); + CloseHandle (tok); + conn->revert_to_self (); + if (!user) + { + error_code (EACCES); + return; + } + LSA_OBJECT_ATTRIBUTES oa = { 0, 0, 0, 0, 0, 0 }; + HANDLE lsa; + NTSTATUS status = LsaOpenPolicy (NULL, &oa, POLICY_CREATE_SECRET, &lsa); + if (!NT_SUCCESS (status)) + { + error_code (LsaNtStatusToWinError (status)); + return; + } + RtlInitEmptyUnicodeString (&sid, sidbuf, sizeof sidbuf); + RtlConvertSidToUnicodeString (&sid, user->User.Sid, FALSE); + free (user); + RtlInitEmptyUnicodeString (&key, key_name, sizeof key_name); + RtlAppendUnicodeToString (&key, CYGWIN_LSA_KEY_PREFIX); + RtlAppendUnicodeStringToString (&key, &sid); + RtlInitUnicodeString (&data, _parameters.in.passwd); + status = LsaStorePrivateData (lsa, &key, data.Length ? &data : NULL); + if (NT_SUCCESS (status)) + error_code (0); + else + error_code (LsaNtStatusToWinError (status)); + syscall_printf ("Request to set private data returns error %d", error_code ()); + LsaClose (lsa); +} +#endif /* __OUTSIDE_CYGWIN__ */