~ubuntu-branches/ubuntu/vivid/samba/vivid

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/krb5/expand_path.c

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2011-12-21 13:18:04 UTC
  • mfrom: (0.39.21 sid)
  • Revision ID: package-import@ubuntu.com-20111221131804-xtlr39wx6njehxxr
Tags: 2:3.6.1-3ubuntu1
* Merge from Debian testing.  Remaining changes:
  + debian/patches/VERSION.patch:
    - set SAMBA_VERSION_SUFFIX to Ubuntu.
  + debian/patches/error-trans.fix-276472:
    - Add the translation of Unix Error code -ENOTSUP to NT Error Code
    - NT_STATUS_NOT_SUPPORTED to prevent the Permission denied error.
  + debian/smb.conf:
    - add "(Samba, Ubuntu)" to server string.
    - comment out the default [homes] share, and add a comment about
      "valid users = %S" to show users how to restrict access to
      \\server\username to only username.
    - Set 'usershare allow guests', so that usershare admins are 
      allowed to create public shares in addition to authenticated
      ones.
    - add map to guest = Bad user, maps bad username to guest access.
  + debian/samba-common.config:
    - Do not change priority to high if dhclient3 is installed.
    - Use priority medium instead of high for the workgroup question.
  + debian/control:
    - Don't build against or suggest ctdb.
    - Add dependency on samba-common-bin to samba.
  + Add ufw integration:
    - Created debian/samba.ufw.profile
    - debian/rules, debian/samba.dirs, debian/samba.files: install
      profile
    - debian/control: have samba suggest ufw
  + Add apport hook:
    - Created debian/source_samba.py.
    - debian/rules, debian/samba.dirs, debian/samba-common-bin.files: install
  + Switch to upstart:
    - Add debian/samba.{nmbd,smbd}.upstart.
  + debian/samba.logrotate, debian/samba-common.dhcp, debian/samba.if-up:
    - Make them upstart compatible
  + debian/samba.postinst: 
    - Avoid scary pdbedit warnings on first import.
  + debian/samba-common.postinst: Add more informative error message for
    the case where smb.conf was manually deleted
  + debian/patches/fix-debuglevel-name-conflict.patch: don't use 'debug_level'
    as a global variable name in an NSS module 
  + Dropped:
    - debian/patches/error-trans.fix-276472
    - debian/patches/fix-debuglevel-name-conflict.patch

Show diffs side-by-side

added added

removed removed

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