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

« back to all changes in this revision

Viewing changes to source4/heimdal/base/heimbase.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
 * Copyright (c) 2010 Kungliga Tekniska Högskolan
 
3
 * (Royal Institute of Technology, Stockholm, Sweden).
 
4
 * All rights reserved.
 
5
 *
 
6
 * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
 
7
 *
 
8
 * Redistribution and use in source and binary forms, with or without
 
9
 * modification, are permitted provided that the following conditions
 
10
 * are met:
 
11
 *
 
12
 * 1. Redistributions of source code must retain the above copyright
 
13
 *    notice, this list of conditions and the following disclaimer.
 
14
 *
 
15
 * 2. Redistributions in binary form must reproduce the above copyright
 
16
 *    notice, this list of conditions and the following disclaimer in the
 
17
 *    documentation and/or other materials provided with the distribution.
 
18
 *
 
19
 * 3. Neither the name of the Institute nor the names of its contributors
 
20
 *    may be used to endorse or promote products derived from this software
 
21
 *    without specific prior written permission.
 
22
 *
 
23
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 
24
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
25
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
26
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 
27
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
28
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
29
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
30
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
31
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
32
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
33
 * SUCH DAMAGE.
 
34
 */
 
35
 
 
36
#include "baselocl.h"
 
37
#include <syslog.h>
 
38
 
 
39
static heim_base_atomic_type tidglobal = HEIM_TID_USER;
 
40
 
 
41
struct heim_base {
 
42
    heim_type_t isa;
 
43
    heim_base_atomic_type ref_cnt;
 
44
    HEIM_TAILQ_ENTRY(heim_base) autorel;
 
45
    heim_auto_release_t autorelpool;
 
46
    uintptr_t isaextra[3];
 
47
};
 
48
 
 
49
/* specialized version of base */
 
50
struct heim_base_mem {
 
51
    heim_type_t isa;
 
52
    heim_base_atomic_type ref_cnt;
 
53
    HEIM_TAILQ_ENTRY(heim_base) autorel;
 
54
    heim_auto_release_t autorelpool;
 
55
    const char *name;
 
56
    void (*dealloc)(void *);
 
57
    uintptr_t isaextra[1];
 
58
};
 
59
 
 
60
#define PTR2BASE(ptr) (((struct heim_base *)ptr) - 1)
 
61
#define BASE2PTR(ptr) ((void *)(((struct heim_base *)ptr) + 1))
 
62
 
 
63
#ifdef HEIM_BASE_NEED_ATOMIC_MUTEX
 
64
HEIMDAL_MUTEX _heim_base_mutex = HEIMDAL_MUTEX_INITIALIZER;
 
65
#endif
 
66
 
 
67
/*
 
68
 * Auto release structure
 
69
 */
 
70
 
 
71
struct heim_auto_release {
 
72
    HEIM_TAILQ_HEAD(, heim_base) pool;
 
73
    HEIMDAL_MUTEX pool_mutex;
 
74
    struct heim_auto_release *parent;
 
75
};
 
76
 
 
77
 
 
78
/**
 
79
 * Retain object
 
80
 *
 
81
 * @param object to be released, NULL is ok
 
82
 *
 
83
 * @return the same object as passed in
 
84
 */
 
85
 
 
86
void *
 
87
heim_retain(void *ptr)
 
88
{
 
89
    struct heim_base *p = PTR2BASE(ptr);
 
90
 
 
91
    if (ptr == NULL || heim_base_is_tagged(ptr))
 
92
        return ptr;
 
93
 
 
94
    if (p->ref_cnt == heim_base_atomic_max)
 
95
        return ptr;
 
96
 
 
97
    if ((heim_base_atomic_inc(&p->ref_cnt) - 1) == 0)
 
98
        heim_abort("resurection");
 
99
    return ptr;
 
100
}
 
101
 
 
102
/**
 
103
 * Release object, free is reference count reaches zero
 
104
 *
 
105
 * @param object to be released
 
106
 */
 
107
 
 
108
void
 
109
heim_release(void *ptr)
 
110
{
 
111
    heim_base_atomic_type old;
 
112
    struct heim_base *p = PTR2BASE(ptr);
 
113
 
 
114
    if (ptr == NULL || heim_base_is_tagged(ptr))
 
115
        return;
 
116
 
 
117
    if (p->ref_cnt == heim_base_atomic_max)
 
118
        return;
 
119
 
 
120
    old = heim_base_atomic_dec(&p->ref_cnt) + 1;
 
121
 
 
122
    if (old > 1)
 
123
        return;
 
124
 
 
125
    if (old == 1) {
 
126
        heim_auto_release_t ar = p->autorelpool;
 
127
        /* remove from autorel pool list */
 
128
        if (ar) {
 
129
            p->autorelpool = NULL;
 
130
            HEIMDAL_MUTEX_lock(&ar->pool_mutex);
 
131
            HEIM_TAILQ_REMOVE(&ar->pool, p, autorel);
 
132
            HEIMDAL_MUTEX_unlock(&ar->pool_mutex);
 
133
        }
 
134
        if (p->isa->dealloc)
 
135
            p->isa->dealloc(ptr);
 
136
        free(p);
 
137
    } else
 
138
        heim_abort("over release");
 
139
}
 
140
 
 
141
static heim_type_t tagged_isa[9] = {
 
142
    &_heim_number_object,
 
143
    &_heim_null_object,
 
144
    &_heim_bool_object,
 
145
 
 
146
    NULL,
 
147
    NULL,
 
148
    NULL,
 
149
 
 
150
    NULL,
 
151
    NULL,
 
152
    NULL
 
153
};
 
154
 
 
155
heim_type_t
 
156
_heim_get_isa(heim_object_t ptr)
 
157
{
 
158
    struct heim_base *p;
 
159
    if (heim_base_is_tagged(ptr)) {
 
160
        if (heim_base_is_tagged_object(ptr))
 
161
            return tagged_isa[heim_base_tagged_object_tid(ptr)];
 
162
        heim_abort("not a supported tagged type");
 
163
    }
 
164
    p = PTR2BASE(ptr);
 
165
    return p->isa;
 
166
}
 
167
 
 
168
/**
 
169
 * Get type ID of object
 
170
 *
 
171
 * @param object object to get type id of
 
172
 *
 
173
 * @return type id of object
 
174
 */
 
175
 
 
176
heim_tid_t
 
177
heim_get_tid(heim_object_t ptr)
 
178
{
 
179
    heim_type_t isa = _heim_get_isa(ptr);
 
180
    return isa->tid;
 
181
}
 
182
 
 
183
/**
 
184
 * Get hash value of object
 
185
 *
 
186
 * @param object object to get hash value for
 
187
 *
 
188
 * @return a hash value
 
189
 */
 
190
 
 
191
unsigned long
 
192
heim_get_hash(heim_object_t ptr)
 
193
{
 
194
    heim_type_t isa = _heim_get_isa(ptr);
 
195
    if (isa->hash)
 
196
        return isa->hash(ptr);
 
197
    return (unsigned long)ptr;
 
198
}
 
199
 
 
200
/**
 
201
 * Compare two objects, returns 0 if equal, can use used for qsort()
 
202
 * and friends.
 
203
 *
 
204
 * @param a first object to compare
 
205
 * @param b first object to compare
 
206
 *
 
207
 * @return 0 if objects are equal
 
208
 */
 
209
 
 
210
int
 
211
heim_cmp(heim_object_t a, heim_object_t b)
 
212
{
 
213
    heim_tid_t ta, tb;
 
214
    heim_type_t isa;
 
215
 
 
216
    ta = heim_get_tid(a);
 
217
    tb = heim_get_tid(b);
 
218
 
 
219
    if (ta != tb)
 
220
        return ta - tb;
 
221
 
 
222
    isa = _heim_get_isa(a);
 
223
 
 
224
    if (isa->cmp)
 
225
        return isa->cmp(a, b);
 
226
 
 
227
    return (uintptr_t)a - (uintptr_t)b;
 
228
}
 
229
 
 
230
/*
 
231
 * Private - allocates an memory object
 
232
 */
 
233
 
 
234
static void
 
235
memory_dealloc(void *ptr)
 
236
{
 
237
    struct heim_base_mem *p = (struct heim_base_mem *)PTR2BASE(ptr);
 
238
    if (p->dealloc)
 
239
        p->dealloc(ptr);
 
240
}
 
241
 
 
242
struct heim_type_data memory_object = {
 
243
    HEIM_TID_MEMORY,
 
244
    "memory-object",
 
245
    NULL,
 
246
    memory_dealloc,
 
247
    NULL,
 
248
    NULL,
 
249
    NULL
 
250
};
 
251
 
 
252
void *
 
253
heim_alloc(size_t size, const char *name, heim_type_dealloc dealloc)
 
254
{
 
255
    /* XXX use posix_memalign */
 
256
 
 
257
    struct heim_base_mem *p = calloc(1, size + sizeof(*p));
 
258
    if (p == NULL)
 
259
        return NULL;
 
260
    p->isa = &memory_object;
 
261
    p->ref_cnt = 1;
 
262
    p->name = name;
 
263
    p->dealloc = dealloc;
 
264
    return BASE2PTR(p);
 
265
}
 
266
 
 
267
heim_type_t
 
268
_heim_create_type(const char *name,
 
269
                  heim_type_init init,
 
270
                  heim_type_dealloc dealloc,
 
271
                  heim_type_copy copy,
 
272
                  heim_type_cmp cmp,
 
273
                  heim_type_hash hash)
 
274
{
 
275
    heim_type_t type;
 
276
 
 
277
    type = calloc(1, sizeof(*type));
 
278
    if (type == NULL)
 
279
        return NULL;
 
280
 
 
281
    type->tid = heim_base_atomic_inc(&tidglobal);
 
282
    type->name = name;
 
283
    type->init = init;
 
284
    type->dealloc = dealloc;
 
285
    type->copy = copy;
 
286
    type->cmp = cmp;
 
287
    type->hash = hash;
 
288
 
 
289
    return type;
 
290
}
 
291
 
 
292
heim_object_t
 
293
_heim_alloc_object(heim_type_t type, size_t size)
 
294
{
 
295
    /* XXX should use posix_memalign */
 
296
    struct heim_base *p = calloc(1, size + sizeof(*p));
 
297
    if (p == NULL)
 
298
        return NULL;
 
299
    p->isa = type;
 
300
    p->ref_cnt = 1;
 
301
 
 
302
    return BASE2PTR(p);
 
303
}
 
304
 
 
305
heim_tid_t
 
306
_heim_type_get_tid(heim_type_t type)
 
307
{
 
308
    return type->tid;
 
309
}
 
310
 
 
311
/**
 
312
 * Call func once and only once
 
313
 *
 
314
 * @param once pointer to a heim_base_once_t
 
315
 * @param ctx context passed to func
 
316
 * @param func function to be called
 
317
 */
 
318
 
 
319
void
 
320
heim_base_once_f(heim_base_once_t *once, void *ctx, void (*func)(void *))
 
321
{
 
322
#ifdef HAVE_DISPATCH_DISPATCH_H
 
323
    dispatch_once_f(once, ctx, func);
 
324
#else
 
325
    static HEIMDAL_MUTEX mutex = HEIMDAL_MUTEX_INITIALIZER;
 
326
    HEIMDAL_MUTEX_lock(&mutex);
 
327
    if (*once == 0) {
 
328
        *once = 1;
 
329
        HEIMDAL_MUTEX_unlock(&mutex);
 
330
        func(ctx);
 
331
        HEIMDAL_MUTEX_lock(&mutex);
 
332
        *once = 2;
 
333
        HEIMDAL_MUTEX_unlock(&mutex);
 
334
    } else if (*once == 2) {
 
335
        HEIMDAL_MUTEX_unlock(&mutex);
 
336
    } else {
 
337
        HEIMDAL_MUTEX_unlock(&mutex);
 
338
        while (1) {
 
339
            struct timeval tv = { 0, 1000 };
 
340
            select(0, NULL, NULL, NULL, &tv);
 
341
            HEIMDAL_MUTEX_lock(&mutex);
 
342
            if (*once == 2)
 
343
                break;
 
344
            HEIMDAL_MUTEX_unlock(&mutex);
 
345
        }
 
346
        HEIMDAL_MUTEX_unlock(&mutex);
 
347
    }
 
348
#endif
 
349
}
 
350
 
 
351
/**
 
352
 * Abort and log the failure (using syslog)
 
353
 */
 
354
 
 
355
void
 
356
heim_abort(const char *fmt, ...)
 
357
{
 
358
    va_list ap;
 
359
    va_start(ap, fmt);
 
360
    heim_abortv(fmt, ap);
 
361
    va_end(ap);
 
362
}
 
363
 
 
364
/**
 
365
 * Abort and log the failure (using syslog)
 
366
 */
 
367
 
 
368
void
 
369
heim_abortv(const char *fmt, va_list ap)
 
370
{
 
371
    static char str[1024];
 
372
    
 
373
    vsnprintf(str, sizeof(str), fmt, ap);
 
374
    syslog(LOG_ERR, "heim_abort: %s", str);
 
375
    abort();
 
376
}
 
377
 
 
378
/*
 
379
 *
 
380
 */
 
381
 
 
382
static int ar_created = 0;
 
383
static HEIMDAL_thread_key ar_key;
 
384
 
 
385
struct ar_tls {
 
386
    struct heim_auto_release *head;
 
387
    struct heim_auto_release *current;
 
388
    HEIMDAL_MUTEX tls_mutex;
 
389
};
 
390
 
 
391
static void
 
392
ar_tls_delete(void *ptr)
 
393
{
 
394
    struct ar_tls *tls = ptr;
 
395
    if (tls->head)
 
396
        heim_release(tls->head);
 
397
    free(tls);
 
398
}
 
399
 
 
400
static void
 
401
init_ar_tls(void *ptr)
 
402
{
 
403
    int ret;
 
404
    HEIMDAL_key_create(&ar_key, ar_tls_delete, ret);
 
405
    if (ret == 0)
 
406
        ar_created = 1;
 
407
}
 
408
 
 
409
static struct ar_tls *
 
410
autorel_tls(void)
 
411
{
 
412
    static heim_base_once_t once = HEIM_BASE_ONCE_INIT;
 
413
    struct ar_tls *arp;
 
414
    int ret;
 
415
 
 
416
    heim_base_once_f(&once, NULL, init_ar_tls);
 
417
    if (!ar_created)
 
418
        return NULL;
 
419
 
 
420
    arp = HEIMDAL_getspecific(ar_key);
 
421
    if (arp == NULL) {
 
422
 
 
423
        arp = calloc(1, sizeof(*arp));
 
424
        if (arp == NULL)
 
425
            return NULL;
 
426
        HEIMDAL_setspecific(ar_key, arp, ret);
 
427
        if (ret) {
 
428
            free(arp);
 
429
            return NULL;
 
430
        }
 
431
    }
 
432
    return arp;
 
433
 
 
434
}
 
435
 
 
436
static void
 
437
autorel_dealloc(void *ptr)
 
438
{
 
439
    heim_auto_release_t ar = ptr;
 
440
    struct ar_tls *tls;
 
441
 
 
442
    tls = autorel_tls();
 
443
    if (tls == NULL)
 
444
        heim_abort("autorelease pool released on thread w/o autorelease inited");
 
445
 
 
446
    heim_auto_release_drain(ar);
 
447
 
 
448
    if (!HEIM_TAILQ_EMPTY(&ar->pool))
 
449
        heim_abort("pool not empty after draining");
 
450
 
 
451
    HEIMDAL_MUTEX_lock(&tls->tls_mutex);
 
452
    if (tls->current != ptr)
 
453
        heim_abort("autorelease not releaseing top pool");
 
454
 
 
455
    if (tls->current != tls->head)
 
456
        tls->current = ar->parent;
 
457
    HEIMDAL_MUTEX_unlock(&tls->tls_mutex);
 
458
}
 
459
 
 
460
static int
 
461
autorel_cmp(void *a, void *b)
 
462
{
 
463
    return (a == b);
 
464
}
 
465
 
 
466
static unsigned long
 
467
autorel_hash(void *ptr)
 
468
{
 
469
    return (unsigned long)ptr;
 
470
}
 
471
 
 
472
 
 
473
static struct heim_type_data _heim_autorel_object = {
 
474
    HEIM_TID_AUTORELEASE,
 
475
    "autorelease-pool",
 
476
    NULL,
 
477
    autorel_dealloc,
 
478
    NULL,
 
479
    autorel_cmp,
 
480
    autorel_hash
 
481
};
 
482
 
 
483
/**
 
484
 *
 
485
 */
 
486
 
 
487
heim_auto_release_t
 
488
heim_auto_release_create(void)
 
489
{
 
490
    struct ar_tls *tls = autorel_tls();
 
491
    heim_auto_release_t ar;
 
492
 
 
493
    if (tls == NULL)
 
494
        heim_abort("Failed to create/get autorelease head");
 
495
 
 
496
    ar = _heim_alloc_object(&_heim_autorel_object, sizeof(struct heim_auto_release));
 
497
    if (ar) {
 
498
        HEIMDAL_MUTEX_lock(&tls->tls_mutex);
 
499
        if (tls->head == NULL)
 
500
            tls->head = ar;
 
501
        ar->parent = tls->current;
 
502
        tls->current = ar;
 
503
        HEIMDAL_MUTEX_unlock(&tls->tls_mutex);
 
504
    }
 
505
 
 
506
    return ar;
 
507
}
 
508
 
 
509
/**
 
510
 * Mark the current object as a
 
511
 */
 
512
 
 
513
void
 
514
heim_auto_release(heim_object_t ptr)
 
515
{
 
516
    struct heim_base *p = PTR2BASE(ptr);
 
517
    struct ar_tls *tls = autorel_tls();
 
518
    heim_auto_release_t ar;
 
519
 
 
520
    if (ptr == NULL || heim_base_is_tagged(ptr))
 
521
        return;
 
522
 
 
523
    /* drop from old pool */
 
524
    if ((ar = p->autorelpool) != NULL) {
 
525
        HEIMDAL_MUTEX_lock(&ar->pool_mutex);
 
526
        HEIM_TAILQ_REMOVE(&ar->pool, p, autorel);
 
527
        p->autorelpool = NULL;
 
528
        HEIMDAL_MUTEX_unlock(&ar->pool_mutex);
 
529
    }
 
530
 
 
531
    if (tls == NULL || (ar = tls->current) == NULL)
 
532
        heim_abort("no auto relase pool in place, would leak");
 
533
 
 
534
    HEIMDAL_MUTEX_lock(&ar->pool_mutex);
 
535
    HEIM_TAILQ_INSERT_HEAD(&ar->pool, p, autorel);
 
536
    p->autorelpool = ar;
 
537
    HEIMDAL_MUTEX_unlock(&ar->pool_mutex);
 
538
}
 
539
 
 
540
/**
 
541
 *
 
542
 */
 
543
 
 
544
void
 
545
heim_auto_release_drain(heim_auto_release_t autorel)
 
546
{
 
547
    heim_object_t obj;
 
548
 
 
549
    /* release all elements on the tail queue */
 
550
 
 
551
    HEIMDAL_MUTEX_lock(&autorel->pool_mutex);
 
552
    while(!HEIM_TAILQ_EMPTY(&autorel->pool)) {
 
553
        obj = HEIM_TAILQ_FIRST(&autorel->pool);
 
554
        HEIMDAL_MUTEX_unlock(&autorel->pool_mutex);
 
555
        heim_release(BASE2PTR(obj));
 
556
        HEIMDAL_MUTEX_lock(&autorel->pool_mutex);
 
557
    }
 
558
    HEIMDAL_MUTEX_unlock(&autorel->pool_mutex);
 
559
}