xref: /minix3/crypto/external/bsd/heimdal/dist/lib/krb5/expand_path.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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