tdf#154285 Check upper bound of arguments in SbRtl_Minute function
[LibreOffice.git] / extensions / source / config / WinUserInfo / WinUserInfoBe.cxx
blobb4a7b89f045a8ef340440905f75d4641c466bf9a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include "WinUserInfoBe.hxx"
12 #include <com/sun/star/beans/Optional.hpp>
13 #include <comphelper/base64.hxx>
14 #include <comphelper/configuration.hxx>
15 #include <cppuhelper/supportsservice.hxx>
16 #include <map>
17 #include <o3tl/char16_t2wchar_t.hxx>
18 #include <comphelper/diagnose_ex.hxx>
19 #include <officecfg/UserProfile.hxx>
21 #include <Iads.h>
22 #include <Adshlp.h>
23 #include <Lmcons.h>
24 #define SECURITY_WIN32
25 #include <Security.h>
27 #include <systools/win32/comtools.hxx>
28 #include <systools/win32/oleauto.hxx>
30 namespace extensions
32 namespace config
34 namespace WinUserInfo
36 class WinUserInfoBe_Impl
38 public:
39 virtual ~WinUserInfoBe_Impl(){};
40 virtual OUString GetGivenName() = 0;
41 virtual OUString GetSn() { return ""; }
42 virtual OUString GetFathersname() { return ""; }
43 virtual OUString GetInitials() { return ""; }
44 virtual OUString GetStreet() { return ""; }
45 virtual OUString GetCity() { return ""; }
46 virtual OUString GetState() { return ""; }
47 virtual OUString GetApartment() { return ""; }
48 virtual OUString GetPostalCode() { return ""; }
49 virtual OUString GetCountry() { return ""; }
50 virtual OUString GetOrganization() { return ""; }
51 virtual OUString GetPosition() { return ""; }
52 virtual OUString GetTitle() { return ""; }
53 virtual OUString GetHomePhone() { return ""; }
54 virtual OUString GetTelephoneNumber() { return ""; }
55 virtual OUString GetFaxNumber() { return ""; }
56 virtual OUString GetMail() { return ""; }
62 namespace
64 constexpr OUString _givenname(u"givenname"_ustr);
65 constexpr OUString _sn(u"sn"_ustr);
66 constexpr char _fathersname[]("fathersname");
67 constexpr OUString _initials(u"initials"_ustr);
68 constexpr OUString _street(u"street"_ustr);
69 constexpr OUString _l(u"l"_ustr);
70 constexpr OUString _st(u"st"_ustr);
71 constexpr char _apartment[]("apartment");
72 constexpr OUString _postalcode(u"postalcode"_ustr);
73 constexpr OUString _c(u"c"_ustr);
74 constexpr OUString _o(u"o"_ustr);
75 constexpr char _position[]("position");
76 constexpr OUString _title(u"title"_ustr);
77 constexpr OUString _homephone(u"homephone"_ustr);
78 constexpr OUString _telephonenumber(u"telephonenumber"_ustr);
79 constexpr OUString _facsimiletelephonenumber(u"facsimiletelephonenumber"_ustr);
80 constexpr OUString _mail(u"mail"_ustr);
82 // Backend class implementing access to Active Directory user data. It caches its encoded data
83 // in a configuration entry, to allow reusing it when user later doesn't have access to AD DC
84 // (otherwise the user would get different data when connected vs not connected).
85 class ADsUserAccess : public extensions::config::WinUserInfo::WinUserInfoBe_Impl
87 public:
88 ADsUserAccess()
90 try
92 sal::systools::CoInitializeGuard aCoInitializeGuard(COINIT_APARTMENTTHREADED);
94 sal::systools::COMReference<IADsADSystemInfo> pADsys(CLSID_ADSystemInfo, nullptr,
95 CLSCTX_INPROC_SERVER);
97 sal::systools::BStr sUserDN;
98 sal::systools::ThrowIfFailed(pADsys->get_UserName(&sUserDN), "get_UserName failed");
99 // If this user is an AD user, then without an active connection to the domain, all the
100 // above will succeed, and m_sUserDN will be correctly initialized, but the following
101 // call to ADsGetObject will fail, and we will attempt reading cached values.
102 m_sUserDN = sUserDN;
103 OUString sLdapUserDN = "LDAP://" + m_sUserDN;
104 sal::systools::COMReference<IADsUser> pUser;
105 sal::systools::ThrowIfFailed(ADsGetObject(o3tl::toW(sLdapUserDN.getStr()), IID_IADsUser,
106 reinterpret_cast<void**>(&pUser)),
107 "ADsGetObject failed");
108 // Fetch all the required information right now, when we know to have access to AD
109 // (later the connection may already be lost)
110 m_aMap[_givenname] = Str(pUser, &IADsUser::get_FirstName);
111 m_aMap[_sn] = Str(pUser, &IADsUser::get_LastName);
112 m_aMap[_initials] = Str(pUser, L"initials");
113 m_aMap[_street] = Str(pUser, L"streetAddress");
114 m_aMap[_l] = Str(pUser, L"l");
115 m_aMap[_st] = Str(pUser, L"st");
116 m_aMap[_postalcode] = Str(pUser, L"postalCode");
117 m_aMap[_c] = Str(pUser, L"co");
118 m_aMap[_o] = Str(pUser, L"company");
119 m_aMap[_title] = Str(pUser, &IADsUser::get_Title);
120 m_aMap[_homephone] = Str(pUser, L"homePhone");
121 m_aMap[_telephonenumber] = Str(pUser, L"TelephoneNumber");
122 m_aMap[_facsimiletelephonenumber] = Str(pUser, L"facsimileTelephoneNumber");
123 m_aMap[_mail] = Str(pUser, &IADsUser::get_EmailAddress);
125 CacheData();
127 catch (sal::systools::ComError&)
129 // Maybe we temporarily lost connection to AD; try to get cached data
130 GetCachedData();
134 virtual OUString GetGivenName() override { return m_aMap[_givenname]; }
135 virtual OUString GetSn() override { return m_aMap[_sn]; }
136 virtual OUString GetInitials() override { return m_aMap[_initials]; }
137 virtual OUString GetStreet() override { return m_aMap[_street]; }
138 virtual OUString GetCity() override { return m_aMap[_l]; }
139 virtual OUString GetState() override { return m_aMap[_st]; }
140 virtual OUString GetPostalCode() override { return m_aMap[_postalcode]; }
141 virtual OUString GetCountry() override { return m_aMap[_c]; }
142 virtual OUString GetOrganization() override { return m_aMap[_o]; }
143 virtual OUString GetTitle() override { return m_aMap[_title]; }
144 virtual OUString GetHomePhone() override { return m_aMap[_homephone]; }
145 virtual OUString GetTelephoneNumber() override { return m_aMap[_telephonenumber]; }
146 virtual OUString GetFaxNumber() override { return m_aMap[_facsimiletelephonenumber]; }
147 virtual OUString GetMail() override { return m_aMap[_mail]; }
149 private:
150 typedef HRESULT (__stdcall IADsUser::*getstrfunc)(BSTR*);
151 static OUString Str(IADsUser* pUser, getstrfunc func)
153 sal::systools::BStr sBstr;
154 if (FAILED((pUser->*func)(&sBstr)))
155 return "";
156 return OUString(sBstr);
158 static OUString Str(IADsUser* pUser, const wchar_t* property)
160 struct AutoVariant : public VARIANT
162 AutoVariant() { VariantInit(this); }
163 ~AutoVariant() { VariantClear(this); }
164 } varArr;
165 if (FAILED(pUser->GetEx(sal::systools::BStr(o3tl::toU(property)), &varArr)))
166 return "";
167 SAFEARRAY* sa = V_ARRAY(&varArr);
168 LONG nStart, nEnd;
169 if (FAILED(SafeArrayGetLBound(sa, 1, &nStart)) || FAILED(SafeArrayGetUBound(sa, 1, &nEnd)))
170 return "";
171 AutoVariant varItem;
172 for (LONG i = nStart; i <= nEnd; i++)
174 if (FAILED(SafeArrayGetElement(sa, &i, &varItem)))
175 continue;
176 if (varItem.vt == VT_BSTR)
177 return OUString(o3tl::toU(V_BSTR(&varItem)));
178 VariantClear(&varItem);
180 return "";
183 void CacheData()
187 OUString sCachedData = "user=" + m_sUserDN // user DN
188 + "\0" + _givenname + "=" + GetGivenName() // 1st name
189 + "\0" + _sn + "=" + GetSn() // sn
190 + "\0" + _initials + "=" + GetInitials() // initials
191 + "\0" + _street + "=" + GetStreet() // street
192 + "\0" + _l + "=" + GetCity() // l
193 + "\0" + _st + "=" + GetState() // st
194 + "\0" + _postalcode + "=" + GetPostalCode() // p.code
195 + "\0" + _c + "=" + GetCountry() // c
196 + "\0" + _o + "=" + GetOrganization() // o
197 + "\0" + _title + "=" + GetTitle() // title
198 + "\0" + _homephone + "=" + GetHomePhone() // h.phone
199 + "\0" + _telephonenumber + "=" + GetTelephoneNumber() // tel
200 + "\0" + _facsimiletelephonenumber + "=" + GetFaxNumber() // fax
201 + "\0" + _mail + "=" + GetMail(); // mail
202 const css::uno::Sequence<sal_Int8> seqCachedData(
203 reinterpret_cast<const sal_Int8*>(sCachedData.getStr()),
204 sCachedData.getLength() * sizeof(sal_Unicode));
205 OUStringBuffer sOutBuf;
206 comphelper::Base64::encode(sOutBuf, seqCachedData);
208 std::shared_ptr<comphelper::ConfigurationChanges> batch(
209 comphelper::ConfigurationChanges::create());
210 officecfg::UserProfile::WinUserInfo::Cache::set(sOutBuf.makeStringAndClear(), batch);
211 batch->commit();
213 catch (const css::uno::Exception&)
215 TOOLS_WARN_EXCEPTION("extensions.config",
216 "ADsUserAccess: access to configuration data failed:");
220 void GetCachedData()
222 if (m_sUserDN.isEmpty())
223 throw css::uno::RuntimeException();
225 OUString sCache = officecfg::UserProfile::WinUserInfo::Cache::get();
227 if (sCache.isEmpty())
228 throw css::uno::RuntimeException();
231 css::uno::Sequence<sal_Int8> seqCachedData;
232 comphelper::Base64::decode(seqCachedData, sCache);
233 sCache = OUString(reinterpret_cast<const sal_Unicode*>(seqCachedData.getConstArray()),
234 seqCachedData.getLength() / sizeof(sal_Unicode));
237 OUString sUserDN;
238 std::map<const OUString, OUString> aMap;
239 sal_Int32 nIndex = 0;
242 const OUString sEntry = sCache.getToken(0, '\0', nIndex);
243 sal_Int32 nEqIndex = 0;
244 const OUString sEntryName = sEntry.getToken(0, '=', nEqIndex);
245 OUString sEntryVal;
246 if (nEqIndex >= 0)
247 sEntryVal = sEntry.copy(nEqIndex);
248 if (sEntryName == "user")
249 sUserDN = sEntryVal;
250 else
251 aMap[sEntryName] = sEntryVal;
252 } while (nIndex >= 0);
254 if (sUserDN != m_sUserDN)
255 throw css::uno::RuntimeException();
256 m_aMap = std::move(aMap);
259 OUString m_sUserDN; // used to check if the cached data is for current user
260 std::map<const OUString, OUString> m_aMap;
263 class SysInfoUserAccess : public extensions::config::WinUserInfo::WinUserInfoBe_Impl
265 public:
266 SysInfoUserAccess()
270 ULONG nSize = 0;
271 GetUserNameExW(NameDisplay, nullptr, &nSize);
272 if (GetLastError() != ERROR_MORE_DATA)
273 throw css::uno::RuntimeException();
274 auto pNameBuf(std::make_unique<wchar_t[]>(nSize));
275 if (!GetUserNameExW(NameDisplay, pNameBuf.get(), &nSize))
276 throw css::uno::RuntimeException();
277 m_sName = o3tl::toU(pNameBuf.get());
279 catch (css::uno::RuntimeException&)
281 // GetUserNameEx may fail in some cases (e.g., for built-in AD domain
282 // administrator account on non-DC systems), where GetUserName will
283 // still give a name.
284 DWORD nSize = UNLEN + 1;
285 auto pNameBuf(std::make_unique<wchar_t[]>(nSize));
286 if (!GetUserNameW(pNameBuf.get(), &nSize))
287 throw css::uno::RuntimeException();
288 m_sName = o3tl::toU(pNameBuf.get());
292 virtual OUString GetGivenName() override { return m_sName; }
294 private:
295 OUString m_sName;
299 namespace extensions
301 namespace config
303 namespace WinUserInfo
305 WinUserInfoBe::WinUserInfoBe()
306 : WinUserInfoMutexHolder()
307 , BackendBase(mMutex)
311 m_pImpl.reset(new ADsUserAccess());
313 catch (css::uno::RuntimeException&)
315 m_pImpl.reset(new SysInfoUserAccess);
319 WinUserInfoBe::~WinUserInfoBe() {}
321 void WinUserInfoBe::setPropertyValue(OUString const&, css::uno::Any const&)
323 throw css::lang::IllegalArgumentException("setPropertyValue not supported",
324 static_cast<cppu::OWeakObject*>(this), -1);
327 css::uno::Any WinUserInfoBe::getPropertyValue(OUString const& PropertyName)
329 OUString sValue;
330 // Only process the first argument of possibly multiple space- or comma-separated arguments
331 OUString sToken = PropertyName.getToken(0, ' ').getToken(0, ',');
332 if (sToken == _givenname)
334 sValue = m_pImpl->GetGivenName();
336 else if (sToken == _sn)
338 sValue = m_pImpl->GetSn();
340 else if (sToken == _fathersname)
342 sValue = m_pImpl->GetFathersname();
344 else if (sToken == _initials)
346 sValue = m_pImpl->GetInitials();
348 else if (sToken == _street)
350 sValue = m_pImpl->GetStreet();
352 else if (sToken == _l)
354 sValue = m_pImpl->GetCity();
356 else if (sToken == _st)
358 sValue = m_pImpl->GetState();
360 else if (sToken == _apartment)
362 sValue = m_pImpl->GetApartment();
364 else if (sToken == _postalcode)
366 sValue = m_pImpl->GetPostalCode();
368 else if (sToken == _c)
370 sValue = m_pImpl->GetCountry();
372 else if (sToken == _o)
374 sValue = m_pImpl->GetOrganization();
376 else if (sToken == _position)
378 sValue = m_pImpl->GetPosition();
380 else if (sToken == _title)
382 sValue = m_pImpl->GetTitle();
384 else if (sToken == _homephone)
386 sValue = m_pImpl->GetHomePhone();
388 else if (sToken == _telephonenumber)
390 sValue = m_pImpl->GetTelephoneNumber();
392 else if (sToken == _facsimiletelephonenumber)
394 sValue = m_pImpl->GetFaxNumber();
396 else if (sToken == _mail)
398 sValue = m_pImpl->GetMail();
400 else
401 throw css::beans::UnknownPropertyException(sToken, static_cast<cppu::OWeakObject*>(this));
403 return css::uno::Any(css::beans::Optional<css::uno::Any>(
404 !sValue.isEmpty(), sValue.isEmpty() ? css::uno::Any() : css::uno::Any(sValue)));
407 OUString SAL_CALL WinUserInfoBe::getImplementationName()
409 return "com.sun.star.comp.configuration.backend.WinUserInfoBe";
412 sal_Bool SAL_CALL WinUserInfoBe::supportsService(const OUString& aServiceName)
414 return cppu::supportsService(this, aServiceName);
417 css::uno::Sequence<OUString> SAL_CALL WinUserInfoBe::getSupportedServiceNames()
419 return { "com.sun.star.configuration.backend.WinUserInfoBe" };
425 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
426 extensions_WinUserInfoBe_get_implementation(css::uno::XComponentContext*,
427 css::uno::Sequence<css::uno::Any> const&)
429 return cppu::acquire(new extensions::config::WinUserInfo::WinUserInfoBe());
432 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */