1*0a6a1f1dSLionel Sambuc /* $NetBSD: expand_path.c,v 1.1.1.2 2014/04/24 12:45:50 pettai Exp $ */
2ebfedea0SLionel Sambuc
3ebfedea0SLionel Sambuc
4ebfedea0SLionel Sambuc /***********************************************************************
5ebfedea0SLionel Sambuc * Copyright (c) 2009, Secure Endpoints Inc.
6ebfedea0SLionel Sambuc * All rights reserved.
7ebfedea0SLionel Sambuc *
8ebfedea0SLionel Sambuc * Redistribution and use in source and binary forms, with or without
9ebfedea0SLionel Sambuc * modification, are permitted provided that the following conditions
10ebfedea0SLionel Sambuc * are met:
11ebfedea0SLionel Sambuc *
12ebfedea0SLionel Sambuc * - Redistributions of source code must retain the above copyright
13ebfedea0SLionel Sambuc * notice, this list of conditions and the following disclaimer.
14ebfedea0SLionel Sambuc *
15ebfedea0SLionel Sambuc * - Redistributions in binary form must reproduce the above copyright
16ebfedea0SLionel Sambuc * notice, this list of conditions and the following disclaimer in
17ebfedea0SLionel Sambuc * the documentation and/or other materials provided with the
18ebfedea0SLionel Sambuc * distribution.
19ebfedea0SLionel Sambuc *
20ebfedea0SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21ebfedea0SLionel Sambuc * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22ebfedea0SLionel Sambuc * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23ebfedea0SLionel Sambuc * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24ebfedea0SLionel Sambuc * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25ebfedea0SLionel Sambuc * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26ebfedea0SLionel Sambuc * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27ebfedea0SLionel Sambuc * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28ebfedea0SLionel Sambuc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29ebfedea0SLionel Sambuc * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30ebfedea0SLionel Sambuc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31ebfedea0SLionel Sambuc * OF THE POSSIBILITY OF SUCH DAMAGE.
32ebfedea0SLionel Sambuc *
33ebfedea0SLionel Sambuc **********************************************************************/
34ebfedea0SLionel Sambuc
35ebfedea0SLionel Sambuc #include "krb5_locl.h"
36ebfedea0SLionel Sambuc
37ebfedea0SLionel Sambuc typedef int PTYPE;
38ebfedea0SLionel Sambuc
39ebfedea0SLionel Sambuc #ifdef _WIN32
40ebfedea0SLionel Sambuc #include <shlobj.h>
41ebfedea0SLionel Sambuc #include <sddl.h>
42ebfedea0SLionel Sambuc
43ebfedea0SLionel Sambuc /*
44ebfedea0SLionel Sambuc * Expand a %{TEMP} token
45ebfedea0SLionel Sambuc *
46ebfedea0SLionel Sambuc * The %{TEMP} token expands to the temporary path for the current
47ebfedea0SLionel Sambuc * user as returned by GetTempPath().
48ebfedea0SLionel Sambuc *
49ebfedea0SLionel Sambuc * @note: Since the GetTempPath() function relies on the TMP or TEMP
50ebfedea0SLionel Sambuc * environment variables, this function will failover to the system
51ebfedea0SLionel Sambuc * temporary directory until the user profile is loaded. In addition,
52ebfedea0SLionel Sambuc * the returned path may or may not exist.
53ebfedea0SLionel Sambuc */
54ebfedea0SLionel Sambuc static int
_expand_temp_folder(krb5_context context,PTYPE param,const char * postfix,char ** ret)55ebfedea0SLionel Sambuc _expand_temp_folder(krb5_context context, PTYPE param, const char *postfix, char **ret)
56ebfedea0SLionel Sambuc {
57ebfedea0SLionel Sambuc TCHAR tpath[MAX_PATH];
58ebfedea0SLionel Sambuc size_t len;
59ebfedea0SLionel Sambuc
60ebfedea0SLionel Sambuc if (!GetTempPath(sizeof(tpath)/sizeof(tpath[0]), tpath)) {
61ebfedea0SLionel Sambuc if (context)
62ebfedea0SLionel Sambuc krb5_set_error_message(context, EINVAL,
63ebfedea0SLionel Sambuc "Failed to get temporary path (GLE=%d)",
64ebfedea0SLionel Sambuc GetLastError());
65ebfedea0SLionel Sambuc return EINVAL;
66ebfedea0SLionel Sambuc }
67ebfedea0SLionel Sambuc
68ebfedea0SLionel Sambuc len = strlen(tpath);
69ebfedea0SLionel Sambuc
70ebfedea0SLionel Sambuc if (len > 0 && tpath[len - 1] == '\\')
71ebfedea0SLionel Sambuc tpath[len - 1] = '\0';
72ebfedea0SLionel Sambuc
73ebfedea0SLionel Sambuc *ret = strdup(tpath);
74ebfedea0SLionel Sambuc
75ebfedea0SLionel Sambuc if (*ret == NULL) {
76ebfedea0SLionel Sambuc if (context)
77ebfedea0SLionel Sambuc krb5_set_error_message(context, ENOMEM, "strdup - Out of memory");
78ebfedea0SLionel Sambuc return ENOMEM;
79ebfedea0SLionel Sambuc }
80ebfedea0SLionel Sambuc
81ebfedea0SLionel Sambuc return 0;
82ebfedea0SLionel Sambuc }
83ebfedea0SLionel Sambuc
84ebfedea0SLionel Sambuc extern HINSTANCE _krb5_hInstance;
85ebfedea0SLionel Sambuc
86ebfedea0SLionel Sambuc /*
87ebfedea0SLionel Sambuc * Expand a %{BINDIR} token
88ebfedea0SLionel Sambuc *
89ebfedea0SLionel Sambuc * This is also used to expand a few other tokens on Windows, since
90ebfedea0SLionel Sambuc * most of the executable binaries end up in the same directory. The
91ebfedea0SLionel Sambuc * "bin" directory is considered to be the directory in which the
92ebfedea0SLionel Sambuc * krb5.dll is located.
93ebfedea0SLionel Sambuc */
94ebfedea0SLionel Sambuc static int
_expand_bin_dir(krb5_context context,PTYPE param,const char * postfix,char ** ret)95ebfedea0SLionel Sambuc _expand_bin_dir(krb5_context context, PTYPE param, const char *postfix, char **ret)
96ebfedea0SLionel Sambuc {
97ebfedea0SLionel Sambuc TCHAR path[MAX_PATH];
98ebfedea0SLionel Sambuc TCHAR *lastSlash;
99ebfedea0SLionel Sambuc DWORD nc;
100ebfedea0SLionel Sambuc
101ebfedea0SLionel Sambuc nc = GetModuleFileName(_krb5_hInstance, path, sizeof(path)/sizeof(path[0]));
102ebfedea0SLionel Sambuc if (nc == 0 ||
103ebfedea0SLionel Sambuc nc == sizeof(path)/sizeof(path[0])) {
104ebfedea0SLionel Sambuc return EINVAL;
105ebfedea0SLionel Sambuc }
106ebfedea0SLionel Sambuc
107ebfedea0SLionel Sambuc lastSlash = strrchr(path, '\\');
108ebfedea0SLionel Sambuc if (lastSlash != NULL) {
109ebfedea0SLionel Sambuc TCHAR *fslash = strrchr(lastSlash, '/');
110ebfedea0SLionel Sambuc
111ebfedea0SLionel Sambuc if (fslash != NULL)
112ebfedea0SLionel Sambuc lastSlash = fslash;
113ebfedea0SLionel Sambuc
114ebfedea0SLionel Sambuc *lastSlash = '\0';
115ebfedea0SLionel Sambuc }
116ebfedea0SLionel Sambuc
117ebfedea0SLionel Sambuc if (postfix) {
118ebfedea0SLionel Sambuc if (strlcat(path, postfix, sizeof(path)/sizeof(path[0])) >= sizeof(path)/sizeof(path[0]))
119ebfedea0SLionel Sambuc return EINVAL;
120ebfedea0SLionel Sambuc }
121ebfedea0SLionel Sambuc
122ebfedea0SLionel Sambuc *ret = strdup(path);
123ebfedea0SLionel Sambuc if (*ret == NULL)
124ebfedea0SLionel Sambuc return ENOMEM;
125ebfedea0SLionel Sambuc
126ebfedea0SLionel Sambuc return 0;
127ebfedea0SLionel Sambuc }
128ebfedea0SLionel Sambuc
129ebfedea0SLionel Sambuc /*
130ebfedea0SLionel Sambuc * Expand a %{USERID} token
131ebfedea0SLionel Sambuc *
132ebfedea0SLionel Sambuc * The %{USERID} token expands to the string representation of the
133ebfedea0SLionel Sambuc * user's SID. The user account that will be used is the account
134ebfedea0SLionel Sambuc * corresponding to the current thread's security token. This means
135ebfedea0SLionel Sambuc * that:
136ebfedea0SLionel Sambuc *
137ebfedea0SLionel Sambuc * - If the current thread token has the anonymous impersonation
138ebfedea0SLionel Sambuc * level, the call will fail.
139ebfedea0SLionel Sambuc *
140ebfedea0SLionel Sambuc * - If the current thread is impersonating a token at
141ebfedea0SLionel Sambuc * SecurityIdentification level the call will fail.
142ebfedea0SLionel Sambuc *
143ebfedea0SLionel Sambuc */
144ebfedea0SLionel Sambuc static int
_expand_userid(krb5_context context,PTYPE param,const char * postfix,char ** ret)145ebfedea0SLionel Sambuc _expand_userid(krb5_context context, PTYPE param, const char *postfix, char **ret)
146ebfedea0SLionel Sambuc {
147ebfedea0SLionel Sambuc int rv = EINVAL;
148ebfedea0SLionel Sambuc HANDLE hThread = NULL;
149ebfedea0SLionel Sambuc HANDLE hToken = NULL;
150ebfedea0SLionel Sambuc PTOKEN_OWNER pOwner = NULL;
151ebfedea0SLionel Sambuc DWORD len = 0;
152ebfedea0SLionel Sambuc LPTSTR strSid = NULL;
153ebfedea0SLionel Sambuc
154ebfedea0SLionel Sambuc hThread = GetCurrentThread();
155ebfedea0SLionel Sambuc
156ebfedea0SLionel Sambuc if (!OpenThreadToken(hThread, TOKEN_QUERY,
157ebfedea0SLionel Sambuc FALSE, /* Open the thread token as the
158ebfedea0SLionel Sambuc current thread user. */
159ebfedea0SLionel Sambuc &hToken)) {
160ebfedea0SLionel Sambuc
161ebfedea0SLionel Sambuc DWORD le = GetLastError();
162ebfedea0SLionel Sambuc
163ebfedea0SLionel Sambuc if (le == ERROR_NO_TOKEN) {
164ebfedea0SLionel Sambuc HANDLE hProcess = GetCurrentProcess();
165ebfedea0SLionel Sambuc
166ebfedea0SLionel Sambuc le = 0;
167ebfedea0SLionel Sambuc if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
168ebfedea0SLionel Sambuc le = GetLastError();
169ebfedea0SLionel Sambuc }
170ebfedea0SLionel Sambuc
171ebfedea0SLionel Sambuc if (le != 0) {
172ebfedea0SLionel Sambuc if (context)
173ebfedea0SLionel Sambuc krb5_set_error_message(context, rv,
174ebfedea0SLionel Sambuc "Can't open thread token (GLE=%d)", le);
175ebfedea0SLionel Sambuc goto _exit;
176ebfedea0SLionel Sambuc }
177ebfedea0SLionel Sambuc }
178ebfedea0SLionel Sambuc
179ebfedea0SLionel Sambuc if (!GetTokenInformation(hToken, TokenOwner, NULL, 0, &len)) {
180ebfedea0SLionel Sambuc if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
181ebfedea0SLionel Sambuc if (context)
182ebfedea0SLionel Sambuc krb5_set_error_message(context, rv,
183ebfedea0SLionel Sambuc "Unexpected error reading token information (GLE=%d)",
184ebfedea0SLionel Sambuc GetLastError());
185ebfedea0SLionel Sambuc goto _exit;
186ebfedea0SLionel Sambuc }
187ebfedea0SLionel Sambuc
188ebfedea0SLionel Sambuc if (len == 0) {
189ebfedea0SLionel Sambuc if (context)
190ebfedea0SLionel Sambuc krb5_set_error_message(context, rv,
191ebfedea0SLionel Sambuc "GetTokenInformation() returned truncated buffer");
192ebfedea0SLionel Sambuc goto _exit;
193ebfedea0SLionel Sambuc }
194ebfedea0SLionel Sambuc
195ebfedea0SLionel Sambuc pOwner = malloc(len);
196ebfedea0SLionel Sambuc if (pOwner == NULL) {
197ebfedea0SLionel Sambuc if (context)
198ebfedea0SLionel Sambuc krb5_set_error_message(context, rv, "Out of memory");
199ebfedea0SLionel Sambuc goto _exit;
200ebfedea0SLionel Sambuc }
201ebfedea0SLionel Sambuc } else {
202ebfedea0SLionel Sambuc if (context)
203ebfedea0SLionel Sambuc krb5_set_error_message(context, rv, "GetTokenInformation() returned truncated buffer");
204ebfedea0SLionel Sambuc goto _exit;
205ebfedea0SLionel Sambuc }
206ebfedea0SLionel Sambuc
207ebfedea0SLionel Sambuc if (!GetTokenInformation(hToken, TokenOwner, pOwner, len, &len)) {
208ebfedea0SLionel Sambuc if (context)
209ebfedea0SLionel Sambuc krb5_set_error_message(context, rv, "GetTokenInformation() failed. GLE=%d", GetLastError());
210ebfedea0SLionel Sambuc goto _exit;
211ebfedea0SLionel Sambuc }
212ebfedea0SLionel Sambuc
213ebfedea0SLionel Sambuc if (!ConvertSidToStringSid(pOwner->Owner, &strSid)) {
214ebfedea0SLionel Sambuc if (context)
215ebfedea0SLionel Sambuc krb5_set_error_message(context, rv, "Can't convert SID to string. GLE=%d", GetLastError());
216ebfedea0SLionel Sambuc goto _exit;
217ebfedea0SLionel Sambuc }
218ebfedea0SLionel Sambuc
219ebfedea0SLionel Sambuc *ret = strdup(strSid);
220ebfedea0SLionel Sambuc if (*ret == NULL && context)
221ebfedea0SLionel Sambuc krb5_set_error_message(context, rv, "Out of memory");
222ebfedea0SLionel Sambuc
223ebfedea0SLionel Sambuc rv = 0;
224ebfedea0SLionel Sambuc
225ebfedea0SLionel Sambuc _exit:
226ebfedea0SLionel Sambuc if (hToken != NULL)
227ebfedea0SLionel Sambuc CloseHandle(hToken);
228ebfedea0SLionel Sambuc
229ebfedea0SLionel Sambuc if (pOwner != NULL)
230ebfedea0SLionel Sambuc free (pOwner);
231ebfedea0SLionel Sambuc
232ebfedea0SLionel Sambuc if (strSid != NULL)
233ebfedea0SLionel Sambuc LocalFree(strSid);
234ebfedea0SLionel Sambuc
235ebfedea0SLionel Sambuc return rv;
236ebfedea0SLionel Sambuc }
237ebfedea0SLionel Sambuc
238ebfedea0SLionel Sambuc /*
239ebfedea0SLionel Sambuc * Expand a folder identified by a CSIDL
240ebfedea0SLionel Sambuc */
241ebfedea0SLionel Sambuc
242ebfedea0SLionel Sambuc static int
_expand_csidl(krb5_context context,PTYPE folder,const char * postfix,char ** ret)243ebfedea0SLionel Sambuc _expand_csidl(krb5_context context, PTYPE folder, const char *postfix, char **ret)
244ebfedea0SLionel Sambuc {
245ebfedea0SLionel Sambuc TCHAR path[MAX_PATH];
246ebfedea0SLionel Sambuc size_t len;
247ebfedea0SLionel Sambuc
248ebfedea0SLionel Sambuc if (SHGetFolderPath(NULL, folder, NULL, SHGFP_TYPE_CURRENT, path) != S_OK) {
249ebfedea0SLionel Sambuc if (context)
250ebfedea0SLionel Sambuc krb5_set_error_message(context, EINVAL, "Unable to determine folder path");
251ebfedea0SLionel Sambuc return EINVAL;
252ebfedea0SLionel Sambuc }
253ebfedea0SLionel Sambuc
254ebfedea0SLionel Sambuc len = strlen(path);
255ebfedea0SLionel Sambuc
256ebfedea0SLionel Sambuc if (len > 0 && path[len - 1] == '\\')
257ebfedea0SLionel Sambuc path[len - 1] = '\0';
258ebfedea0SLionel Sambuc
259ebfedea0SLionel Sambuc if (postfix &&
260ebfedea0SLionel Sambuc strlcat(path, postfix, sizeof(path)/sizeof(path[0])) >= sizeof(path)/sizeof(path[0])) {
261ebfedea0SLionel Sambuc return ENOMEM;
262ebfedea0SLionel Sambuc }
263ebfedea0SLionel Sambuc
264ebfedea0SLionel Sambuc *ret = strdup(path);
265ebfedea0SLionel Sambuc if (*ret == NULL) {
266ebfedea0SLionel Sambuc if (context)
267ebfedea0SLionel Sambuc krb5_set_error_message(context, ENOMEM, "Out of memory");
268ebfedea0SLionel Sambuc return ENOMEM;
269ebfedea0SLionel Sambuc }
270ebfedea0SLionel Sambuc return 0;
271ebfedea0SLionel Sambuc }
272ebfedea0SLionel Sambuc
273ebfedea0SLionel Sambuc #else
274ebfedea0SLionel Sambuc
275ebfedea0SLionel Sambuc static int
_expand_path(krb5_context context,PTYPE param,const char * postfix,char ** ret)276ebfedea0SLionel Sambuc _expand_path(krb5_context context, PTYPE param, const char *postfix, char **ret)
277ebfedea0SLionel Sambuc {
278ebfedea0SLionel Sambuc *ret = strdup(postfix);
279ebfedea0SLionel Sambuc if (*ret == NULL) {
280ebfedea0SLionel Sambuc krb5_set_error_message(context, ENOMEM, "malloc - out of memory");
281ebfedea0SLionel Sambuc return ENOMEM;
282ebfedea0SLionel Sambuc }
283ebfedea0SLionel Sambuc return 0;
284ebfedea0SLionel Sambuc }
285ebfedea0SLionel Sambuc
286ebfedea0SLionel Sambuc static int
_expand_temp_folder(krb5_context context,PTYPE param,const char * postfix,char ** ret)287ebfedea0SLionel Sambuc _expand_temp_folder(krb5_context context, PTYPE param, const char *postfix, char **ret)
288ebfedea0SLionel Sambuc {
289ebfedea0SLionel Sambuc const char *p = NULL;
290ebfedea0SLionel Sambuc
291ebfedea0SLionel Sambuc if (issuid())
292ebfedea0SLionel Sambuc p = getenv("TEMP");
293ebfedea0SLionel Sambuc if (p)
294ebfedea0SLionel Sambuc *ret = strdup(p);
295ebfedea0SLionel Sambuc else
296ebfedea0SLionel Sambuc *ret = strdup("/tmp");
297ebfedea0SLionel Sambuc if (*ret == NULL)
298ebfedea0SLionel Sambuc return ENOMEM;
299ebfedea0SLionel Sambuc return 0;
300ebfedea0SLionel Sambuc }
301ebfedea0SLionel Sambuc
302ebfedea0SLionel Sambuc static int
_expand_userid(krb5_context context,PTYPE param,const char * postfix,char ** str)303ebfedea0SLionel Sambuc _expand_userid(krb5_context context, PTYPE param, const char *postfix, char **str)
304ebfedea0SLionel Sambuc {
305ebfedea0SLionel Sambuc int ret = asprintf(str, "%ld", (unsigned long)getuid());
306ebfedea0SLionel Sambuc if (ret < 0 || *str == NULL)
307ebfedea0SLionel Sambuc return ENOMEM;
308ebfedea0SLionel Sambuc return 0;
309ebfedea0SLionel Sambuc }
310ebfedea0SLionel Sambuc
311ebfedea0SLionel Sambuc
312ebfedea0SLionel Sambuc #endif /* _WIN32 */
313ebfedea0SLionel Sambuc
314ebfedea0SLionel Sambuc /**
315ebfedea0SLionel Sambuc * Expand a %{null} token
316ebfedea0SLionel Sambuc *
317ebfedea0SLionel Sambuc * The expansion of a %{null} token is always the empty string.
318ebfedea0SLionel Sambuc */
319ebfedea0SLionel Sambuc
320ebfedea0SLionel Sambuc static int
_expand_null(krb5_context context,PTYPE param,const char * postfix,char ** ret)321ebfedea0SLionel Sambuc _expand_null(krb5_context context, PTYPE param, const char *postfix, char **ret)
322ebfedea0SLionel Sambuc {
323ebfedea0SLionel Sambuc *ret = strdup("");
324ebfedea0SLionel Sambuc if (*ret == NULL) {
325ebfedea0SLionel Sambuc if (context)
326ebfedea0SLionel Sambuc krb5_set_error_message(context, ENOMEM, "Out of memory");
327ebfedea0SLionel Sambuc return ENOMEM;
328ebfedea0SLionel Sambuc }
329ebfedea0SLionel Sambuc return 0;
330ebfedea0SLionel Sambuc }
331ebfedea0SLionel Sambuc
332ebfedea0SLionel Sambuc
333ebfedea0SLionel Sambuc static const struct token {
334ebfedea0SLionel Sambuc const char * tok;
335ebfedea0SLionel Sambuc int ftype;
336ebfedea0SLionel Sambuc #define FTYPE_CSIDL 0
337ebfedea0SLionel Sambuc #define FTYPE_SPECIAL 1
338ebfedea0SLionel Sambuc
339ebfedea0SLionel Sambuc PTYPE param;
340ebfedea0SLionel Sambuc const char * postfix;
341ebfedea0SLionel Sambuc
342ebfedea0SLionel Sambuc int (*exp_func)(krb5_context, PTYPE, const char *, char **);
343ebfedea0SLionel Sambuc
344ebfedea0SLionel Sambuc #define SPECIALP(f, P) FTYPE_SPECIAL, 0, P, f
345ebfedea0SLionel Sambuc #define SPECIAL(f) SPECIALP(f, NULL)
346ebfedea0SLionel Sambuc
347ebfedea0SLionel Sambuc } tokens[] = {
348ebfedea0SLionel Sambuc #ifdef _WIN32
349ebfedea0SLionel Sambuc #define CSIDLP(C,P) FTYPE_CSIDL, C, P, _expand_csidl
350ebfedea0SLionel Sambuc #define CSIDL(C) CSIDLP(C, NULL)
351ebfedea0SLionel Sambuc
352ebfedea0SLionel Sambuc {"APPDATA", CSIDL(CSIDL_APPDATA)}, /* Roaming application data (for current user) */
353ebfedea0SLionel Sambuc {"COMMON_APPDATA", CSIDL(CSIDL_COMMON_APPDATA)}, /* Application data (all users) */
354ebfedea0SLionel Sambuc {"LOCAL_APPDATA", CSIDL(CSIDL_LOCAL_APPDATA)}, /* Local application data (for current user) */
355ebfedea0SLionel Sambuc {"SYSTEM", CSIDL(CSIDL_SYSTEM)}, /* Windows System folder (e.g. %WINDIR%\System32) */
356ebfedea0SLionel Sambuc {"WINDOWS", CSIDL(CSIDL_WINDOWS)}, /* Windows folder */
357ebfedea0SLionel Sambuc {"USERCONFIG", CSIDLP(CSIDL_APPDATA, "\\" PACKAGE)}, /* Per user Heimdal configuration file path */
358ebfedea0SLionel Sambuc {"COMMONCONFIG", CSIDLP(CSIDL_COMMON_APPDATA, "\\" PACKAGE)}, /* Common Heimdal configuration file path */
359ebfedea0SLionel Sambuc {"LIBDIR", SPECIAL(_expand_bin_dir)},
360ebfedea0SLionel Sambuc {"BINDIR", SPECIAL(_expand_bin_dir)},
361ebfedea0SLionel Sambuc {"LIBEXEC", SPECIAL(_expand_bin_dir)},
362ebfedea0SLionel Sambuc {"SBINDIR", SPECIAL(_expand_bin_dir)},
363ebfedea0SLionel Sambuc #else
364ebfedea0SLionel Sambuc {"LIBDIR", FTYPE_SPECIAL, 0, LIBDIR, _expand_path},
365ebfedea0SLionel Sambuc {"BINDIR", FTYPE_SPECIAL, 0, BINDIR, _expand_path},
366ebfedea0SLionel Sambuc {"LIBEXEC", FTYPE_SPECIAL, 0, LIBEXECDIR, _expand_path},
367ebfedea0SLionel Sambuc {"SBINDIR", FTYPE_SPECIAL, 0, SBINDIR, _expand_path},
368ebfedea0SLionel Sambuc #endif
369ebfedea0SLionel Sambuc {"TEMP", SPECIAL(_expand_temp_folder)},
370ebfedea0SLionel Sambuc {"USERID", SPECIAL(_expand_userid)},
371ebfedea0SLionel Sambuc {"uid", SPECIAL(_expand_userid)},
372ebfedea0SLionel Sambuc {"null", SPECIAL(_expand_null)}
373ebfedea0SLionel Sambuc };
374ebfedea0SLionel Sambuc
375ebfedea0SLionel Sambuc static int
_expand_token(krb5_context context,const char * token,const char * token_end,char ** ret)376ebfedea0SLionel Sambuc _expand_token(krb5_context context,
377ebfedea0SLionel Sambuc const char *token,
378ebfedea0SLionel Sambuc const char *token_end,
379ebfedea0SLionel Sambuc char **ret)
380ebfedea0SLionel Sambuc {
381ebfedea0SLionel Sambuc size_t i;
382ebfedea0SLionel Sambuc
383ebfedea0SLionel Sambuc *ret = NULL;
384ebfedea0SLionel Sambuc
385ebfedea0SLionel Sambuc if (token[0] != '%' || token[1] != '{' || token_end[0] != '}' ||
386ebfedea0SLionel Sambuc token_end - token <= 2) {
387ebfedea0SLionel Sambuc if (context)
388ebfedea0SLionel Sambuc krb5_set_error_message(context, EINVAL,"Invalid token.");
389ebfedea0SLionel Sambuc return EINVAL;
390ebfedea0SLionel Sambuc }
391ebfedea0SLionel Sambuc
392ebfedea0SLionel Sambuc for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) {
393ebfedea0SLionel Sambuc if (!strncmp(token+2, tokens[i].tok, (token_end - token) - 2))
394ebfedea0SLionel Sambuc return tokens[i].exp_func(context, tokens[i].param,
395ebfedea0SLionel Sambuc tokens[i].postfix, ret);
396ebfedea0SLionel Sambuc }
397ebfedea0SLionel Sambuc
398ebfedea0SLionel Sambuc if (context)
399ebfedea0SLionel Sambuc krb5_set_error_message(context, EINVAL, "Invalid token.");
400ebfedea0SLionel Sambuc return EINVAL;
401ebfedea0SLionel Sambuc }
402ebfedea0SLionel Sambuc
403ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_expand_path_tokens(krb5_context context,const char * path_in,char ** ppath_out)404ebfedea0SLionel Sambuc _krb5_expand_path_tokens(krb5_context context,
405ebfedea0SLionel Sambuc const char *path_in,
406ebfedea0SLionel Sambuc char **ppath_out)
407ebfedea0SLionel Sambuc {
408ebfedea0SLionel Sambuc char *tok_begin, *tok_end, *append;
409ebfedea0SLionel Sambuc const char *path_left;
410ebfedea0SLionel Sambuc size_t len = 0;
411ebfedea0SLionel Sambuc
412ebfedea0SLionel Sambuc if (path_in == NULL || *path_in == '\0') {
413ebfedea0SLionel Sambuc *ppath_out = strdup("");
414ebfedea0SLionel Sambuc return 0;
415ebfedea0SLionel Sambuc }
416ebfedea0SLionel Sambuc
417ebfedea0SLionel Sambuc *ppath_out = NULL;
418ebfedea0SLionel Sambuc
419ebfedea0SLionel Sambuc for (path_left = path_in; path_left && *path_left; ) {
420ebfedea0SLionel Sambuc
421ebfedea0SLionel Sambuc tok_begin = strstr(path_left, "%{");
422ebfedea0SLionel Sambuc
423ebfedea0SLionel Sambuc if (tok_begin && tok_begin != path_left) {
424ebfedea0SLionel Sambuc
425ebfedea0SLionel Sambuc append = malloc((tok_begin - path_left) + 1);
426ebfedea0SLionel Sambuc if (append) {
427ebfedea0SLionel Sambuc memcpy(append, path_left, tok_begin - path_left);
428ebfedea0SLionel Sambuc append[tok_begin - path_left] = '\0';
429ebfedea0SLionel Sambuc }
430ebfedea0SLionel Sambuc path_left = tok_begin;
431ebfedea0SLionel Sambuc
432ebfedea0SLionel Sambuc } else if (tok_begin) {
433ebfedea0SLionel Sambuc
434ebfedea0SLionel Sambuc tok_end = strchr(tok_begin, '}');
435ebfedea0SLionel Sambuc if (tok_end == NULL) {
436ebfedea0SLionel Sambuc if (*ppath_out)
437ebfedea0SLionel Sambuc free(*ppath_out);
438ebfedea0SLionel Sambuc *ppath_out = NULL;
439ebfedea0SLionel Sambuc if (context)
440ebfedea0SLionel Sambuc krb5_set_error_message(context, EINVAL, "variable missing }");
441ebfedea0SLionel Sambuc return EINVAL;
442ebfedea0SLionel Sambuc }
443ebfedea0SLionel Sambuc
444ebfedea0SLionel Sambuc if (_expand_token(context, tok_begin, tok_end, &append)) {
445ebfedea0SLionel Sambuc if (*ppath_out)
446ebfedea0SLionel Sambuc free(*ppath_out);
447ebfedea0SLionel Sambuc *ppath_out = NULL;
448ebfedea0SLionel Sambuc return EINVAL;
449ebfedea0SLionel Sambuc }
450ebfedea0SLionel Sambuc
451ebfedea0SLionel Sambuc path_left = tok_end + 1;
452ebfedea0SLionel Sambuc } else {
453ebfedea0SLionel Sambuc
454ebfedea0SLionel Sambuc append = strdup(path_left);
455ebfedea0SLionel Sambuc path_left = NULL;
456ebfedea0SLionel Sambuc
457ebfedea0SLionel Sambuc }
458ebfedea0SLionel Sambuc
459ebfedea0SLionel Sambuc if (append == NULL) {
460ebfedea0SLionel Sambuc
461ebfedea0SLionel Sambuc if (*ppath_out)
462ebfedea0SLionel Sambuc free(*ppath_out);
463ebfedea0SLionel Sambuc *ppath_out = NULL;
464ebfedea0SLionel Sambuc if (context)
465ebfedea0SLionel Sambuc krb5_set_error_message(context, ENOMEM, "malloc - out of memory");
466ebfedea0SLionel Sambuc return ENOMEM;
467ebfedea0SLionel Sambuc
468ebfedea0SLionel Sambuc }
469ebfedea0SLionel Sambuc
470ebfedea0SLionel Sambuc {
471ebfedea0SLionel Sambuc size_t append_len = strlen(append);
472ebfedea0SLionel Sambuc char * new_str = realloc(*ppath_out, len + append_len + 1);
473ebfedea0SLionel Sambuc
474ebfedea0SLionel Sambuc if (new_str == NULL) {
475ebfedea0SLionel Sambuc free(append);
476ebfedea0SLionel Sambuc if (*ppath_out)
477ebfedea0SLionel Sambuc free(*ppath_out);
478ebfedea0SLionel Sambuc *ppath_out = NULL;
479ebfedea0SLionel Sambuc if (context)
480ebfedea0SLionel Sambuc krb5_set_error_message(context, ENOMEM, "malloc - out of memory");
481ebfedea0SLionel Sambuc return ENOMEM;
482ebfedea0SLionel Sambuc }
483ebfedea0SLionel Sambuc
484ebfedea0SLionel Sambuc *ppath_out = new_str;
485ebfedea0SLionel Sambuc memcpy(*ppath_out + len, append, append_len + 1);
486ebfedea0SLionel Sambuc len = len + append_len;
487ebfedea0SLionel Sambuc free(append);
488ebfedea0SLionel Sambuc }
489ebfedea0SLionel Sambuc }
490ebfedea0SLionel Sambuc
491ebfedea0SLionel Sambuc #ifdef _WIN32
492ebfedea0SLionel Sambuc /* Also deal with slashes */
493ebfedea0SLionel Sambuc if (*ppath_out) {
494ebfedea0SLionel Sambuc char * c;
495ebfedea0SLionel Sambuc for (c = *ppath_out; *c; c++)
496ebfedea0SLionel Sambuc if (*c == '/')
497ebfedea0SLionel Sambuc *c = '\\';
498ebfedea0SLionel Sambuc }
499ebfedea0SLionel Sambuc #endif
500ebfedea0SLionel Sambuc
501ebfedea0SLionel Sambuc return 0;
502ebfedea0SLionel Sambuc }
503