~ubuntu-branches/ubuntu/oneiric/samba/oneiric-security

« back to all changes in this revision

Viewing changes to .pc/security-CVE-2011-0719.patch/source3/winbindd/winbindd_dual.c

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2011-03-10 10:03:01 UTC
  • mfrom: (0.39.11 sid)
  • Revision ID: james.westby@ubuntu.com-20110310100301-jfjg41wv0iq05zj4
Tags: 2:3.5.8~dfsg-1ubuntu1
* Merge from debian unstable.  Remaining changes:
  + debian/patches/VERSION.patch:
    - set SAMBA_VERSION_SUFFIX to Ubuntu.
  + 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/mksmbpasswd.awk:
    - Do not add user with UID less than 1000 to smbpasswd
  + debian/control:
    - Make libwbclient0 replace/conflict with hardy's likewise-open.
    - Don't build against or suggest ctdb.
    - Add dependency on samba-common-bin to samba.
    - Add cuups breaks to push the package to aslo upgrade cups (LP: #639768)
  + debian/rules:
    - enable "native" PIE hardening.
    - Add BIND_NOW to maximize benefit of RELRO hardening.
  + 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.
    - Don't ship the /etc/network/if-up.d file.
  + debian/samba.postinst: 
    - Fixed bashism.
    - 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/samba.logrotate: Make it upstart compatible
  + debian/samba-common.dhcp: Fix typo to get a proper parsing in
    /etc/samba/dhcp.
  + Dropped:
    - debian/patches/fix-windows7-print-connection.patch: Merged upstream.
    - debian/patches/security-CVE-2011-0719.patch: Merged upstream. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* 
2
 
   Unix SMB/CIFS implementation.
3
 
 
4
 
   Winbind child daemons
5
 
 
6
 
   Copyright (C) Andrew Tridgell 2002
7
 
   Copyright (C) Volker Lendecke 2004,2005
8
 
 
9
 
   This program is free software; you can redistribute it and/or modify
10
 
   it under the terms of the GNU General Public License as published by
11
 
   the Free Software Foundation; either version 3 of the License, or
12
 
   (at your option) any later version.
13
 
 
14
 
   This program is distributed in the hope that it will be useful,
15
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 
   GNU General Public License for more details.
18
 
 
19
 
   You should have received a copy of the GNU General Public License
20
 
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 
*/
22
 
 
23
 
/*
24
 
 * We fork a child per domain to be able to act non-blocking in the main
25
 
 * winbind daemon. A domain controller thousands of miles away being being
26
 
 * slow replying with a 10.000 user list should not hold up netlogon calls
27
 
 * that can be handled locally.
28
 
 */
29
 
 
30
 
#include "includes.h"
31
 
#include "winbindd.h"
32
 
#include "../../nsswitch/libwbclient/wbc_async.h"
33
 
 
34
 
#undef DBGC_CLASS
35
 
#define DBGC_CLASS DBGC_WINBIND
36
 
 
37
 
extern bool override_logfile;
38
 
extern struct winbindd_methods cache_methods;
39
 
 
40
 
/* Read some data from a client connection */
41
 
 
42
 
static NTSTATUS child_read_request(struct winbindd_cli_state *state)
43
 
{
44
 
        NTSTATUS status;
45
 
 
46
 
        /* Read data */
47
 
 
48
 
        status = read_data(state->sock, (char *)state->request,
49
 
                           sizeof(*state->request));
50
 
 
51
 
        if (!NT_STATUS_IS_OK(status)) {
52
 
                DEBUG(3, ("child_read_request: read_data failed: %s\n",
53
 
                          nt_errstr(status)));
54
 
                return status;
55
 
        }
56
 
 
57
 
        if (state->request->extra_len == 0) {
58
 
                state->request->extra_data.data = NULL;
59
 
                return NT_STATUS_OK;
60
 
        }
61
 
 
62
 
        DEBUG(10, ("Need to read %d extra bytes\n", (int)state->request->extra_len));
63
 
 
64
 
        state->request->extra_data.data =
65
 
                SMB_MALLOC_ARRAY(char, state->request->extra_len + 1);
66
 
 
67
 
        if (state->request->extra_data.data == NULL) {
68
 
                DEBUG(0, ("malloc failed\n"));
69
 
                return NT_STATUS_NO_MEMORY;
70
 
        }
71
 
 
72
 
        /* Ensure null termination */
73
 
        state->request->extra_data.data[state->request->extra_len] = '\0';
74
 
 
75
 
        status= read_data(state->sock, state->request->extra_data.data,
76
 
                          state->request->extra_len);
77
 
 
78
 
        if (!NT_STATUS_IS_OK(status)) {
79
 
                DEBUG(0, ("Could not read extra data: %s\n",
80
 
                          nt_errstr(status)));
81
 
        }
82
 
        return status;
83
 
}
84
 
 
85
 
/*
86
 
 * Do winbind child async request. This is not simply wb_simple_trans. We have
87
 
 * to do the queueing ourselves because while a request is queued, the child
88
 
 * might have crashed, and we have to re-fork it in the _trigger function.
89
 
 */
90
 
 
91
 
struct wb_child_request_state {
92
 
        struct tevent_context *ev;
93
 
        struct winbindd_child *child;
94
 
        struct winbindd_request *request;
95
 
        struct winbindd_response *response;
96
 
};
97
 
 
98
 
static bool fork_domain_child(struct winbindd_child *child);
99
 
 
100
 
static void wb_child_request_trigger(struct tevent_req *req,
101
 
                                            void *private_data);
102
 
static void wb_child_request_done(struct tevent_req *subreq);
103
 
 
104
 
struct tevent_req *wb_child_request_send(TALLOC_CTX *mem_ctx,
105
 
                                         struct tevent_context *ev,
106
 
                                         struct winbindd_child *child,
107
 
                                         struct winbindd_request *request)
108
 
{
109
 
        struct tevent_req *req;
110
 
        struct wb_child_request_state *state;
111
 
 
112
 
        req = tevent_req_create(mem_ctx, &state,
113
 
                                struct wb_child_request_state);
114
 
        if (req == NULL) {
115
 
                return NULL;
116
 
        }
117
 
 
118
 
        state->ev = ev;
119
 
        state->child = child;
120
 
        state->request = request;
121
 
 
122
 
        if (!tevent_queue_add(child->queue, ev, req,
123
 
                              wb_child_request_trigger, NULL)) {
124
 
                tevent_req_nomem(NULL, req);
125
 
                return tevent_req_post(req, ev);
126
 
        }
127
 
        return req;
128
 
}
129
 
 
130
 
static void wb_child_request_trigger(struct tevent_req *req,
131
 
                                     void *private_data)
132
 
{
133
 
        struct wb_child_request_state *state = tevent_req_data(
134
 
                req, struct wb_child_request_state);
135
 
        struct tevent_req *subreq;
136
 
 
137
 
        if ((state->child->pid == 0) && (!fork_domain_child(state->child))) {
138
 
                tevent_req_error(req, errno);
139
 
                return;
140
 
        }
141
 
 
142
 
        subreq = wb_simple_trans_send(state, winbind_event_context(), NULL,
143
 
                                      state->child->sock, state->request);
144
 
        if (tevent_req_nomem(subreq, req)) {
145
 
                return;
146
 
        }
147
 
        tevent_req_set_callback(subreq, wb_child_request_done, req);
148
 
 
149
 
        if (!tevent_req_set_endtime(req, state->ev,
150
 
                                    timeval_current_ofs(300, 0))) {
151
 
                tevent_req_nomem(NULL, req);
152
 
                return;
153
 
        }
154
 
}
155
 
 
156
 
static void wb_child_request_done(struct tevent_req *subreq)
157
 
{
158
 
        struct tevent_req *req = tevent_req_callback_data(
159
 
                subreq, struct tevent_req);
160
 
        struct wb_child_request_state *state = tevent_req_data(
161
 
                req, struct wb_child_request_state);
162
 
        int ret, err;
163
 
 
164
 
        ret = wb_simple_trans_recv(subreq, state, &state->response, &err);
165
 
        TALLOC_FREE(subreq);
166
 
        if (ret == -1) {
167
 
                tevent_req_error(req, err);
168
 
                return;
169
 
        }
170
 
        tevent_req_done(req);
171
 
}
172
 
 
173
 
int wb_child_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
174
 
                          struct winbindd_response **presponse, int *err)
175
 
{
176
 
        struct wb_child_request_state *state = tevent_req_data(
177
 
                req, struct wb_child_request_state);
178
 
 
179
 
        if (tevent_req_is_unix_error(req, err)) {
180
 
                return -1;
181
 
        }
182
 
        *presponse = talloc_move(mem_ctx, &state->response);
183
 
        return 0;
184
 
}
185
 
 
186
 
struct wb_domain_request_state {
187
 
        struct tevent_context *ev;
188
 
        struct winbindd_domain *domain;
189
 
        struct winbindd_request *request;
190
 
        struct winbindd_request *init_req;
191
 
        struct winbindd_response *response;
192
 
};
193
 
 
194
 
static void wb_domain_request_gotdc(struct tevent_req *subreq);
195
 
static void wb_domain_request_initialized(struct tevent_req *subreq);
196
 
static void wb_domain_request_done(struct tevent_req *subreq);
197
 
 
198
 
struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx,
199
 
                                          struct tevent_context *ev,
200
 
                                          struct winbindd_domain *domain,
201
 
                                          struct winbindd_request *request)
202
 
{
203
 
        struct tevent_req *req, *subreq;
204
 
        struct wb_domain_request_state *state;
205
 
 
206
 
        req = tevent_req_create(mem_ctx, &state,
207
 
                                struct wb_domain_request_state);
208
 
        if (req == NULL) {
209
 
                return NULL;
210
 
        }
211
 
 
212
 
        if (domain->initialized) {
213
 
                subreq = wb_child_request_send(state, ev, &domain->child,
214
 
                                               request);
215
 
                if (tevent_req_nomem(subreq, req)) {
216
 
                        return tevent_req_post(req, ev);
217
 
                }
218
 
                tevent_req_set_callback(subreq, wb_domain_request_done, req);
219
 
                return req;
220
 
        }
221
 
 
222
 
        state->domain = domain;
223
 
        state->ev = ev;
224
 
        state->request = request;
225
 
 
226
 
        state->init_req = talloc_zero(state, struct winbindd_request);
227
 
        if (tevent_req_nomem(state->init_req, req)) {
228
 
                return tevent_req_post(req, ev);
229
 
        }
230
 
 
231
 
        if (IS_DC || domain->primary || domain->internal) {
232
 
                /* The primary domain has to find the DC name itself */
233
 
                state->init_req->cmd = WINBINDD_INIT_CONNECTION;
234
 
                fstrcpy(state->init_req->domain_name, domain->name);
235
 
                state->init_req->data.init_conn.is_primary =
236
 
                        domain->primary ? true : false;
237
 
                fstrcpy(state->init_req->data.init_conn.dcname, "");
238
 
 
239
 
                subreq = wb_child_request_send(state, ev, &domain->child,
240
 
                                               state->init_req);
241
 
                if (tevent_req_nomem(subreq, req)) {
242
 
                        return tevent_req_post(req, ev);
243
 
                }
244
 
                tevent_req_set_callback(subreq, wb_domain_request_initialized,
245
 
                                        req);
246
 
                return req;
247
 
        }
248
 
 
249
 
        /*
250
 
         * Ask our DC for a DC name
251
 
         */
252
 
        domain = find_our_domain();
253
 
 
254
 
        /* This is *not* the primary domain, let's ask our DC about a DC
255
 
         * name */
256
 
 
257
 
        state->init_req->cmd = WINBINDD_GETDCNAME;
258
 
        fstrcpy(state->init_req->domain_name, domain->name);
259
 
 
260
 
        subreq = wb_child_request_send(state, ev, &domain->child, request);
261
 
        if (tevent_req_nomem(subreq, req)) {
262
 
                return tevent_req_post(req, ev);
263
 
        }
264
 
        tevent_req_set_callback(subreq, wb_domain_request_gotdc, req);
265
 
        return req;
266
 
}
267
 
 
268
 
static void wb_domain_request_gotdc(struct tevent_req *subreq)
269
 
{
270
 
        struct tevent_req *req = tevent_req_callback_data(
271
 
                subreq, struct tevent_req);
272
 
        struct wb_domain_request_state *state = tevent_req_data(
273
 
                req, struct wb_domain_request_state);
274
 
        struct winbindd_response *response;
275
 
        int ret, err;
276
 
 
277
 
        ret = wb_child_request_recv(subreq, talloc_tos(), &response, &err);
278
 
        TALLOC_FREE(subreq);
279
 
        if (ret == -1) {
280
 
                tevent_req_error(req, err);
281
 
                return;
282
 
        }
283
 
        state->init_req->cmd = WINBINDD_INIT_CONNECTION;
284
 
        fstrcpy(state->init_req->domain_name, state->domain->name);
285
 
        state->init_req->data.init_conn.is_primary = False;
286
 
        fstrcpy(state->init_req->data.init_conn.dcname,
287
 
                response->data.dc_name);
288
 
 
289
 
        TALLOC_FREE(response);
290
 
 
291
 
        subreq = wb_child_request_send(state, state->ev, &state->domain->child,
292
 
                                       state->init_req);
293
 
        if (tevent_req_nomem(subreq, req)) {
294
 
                return;
295
 
        }
296
 
        tevent_req_set_callback(subreq, wb_domain_request_initialized, req);
297
 
}
298
 
 
299
 
static void wb_domain_request_initialized(struct tevent_req *subreq)
300
 
{
301
 
        struct tevent_req *req = tevent_req_callback_data(
302
 
                subreq, struct tevent_req);
303
 
        struct wb_domain_request_state *state = tevent_req_data(
304
 
                req, struct wb_domain_request_state);
305
 
        struct winbindd_response *response;
306
 
        int ret, err;
307
 
 
308
 
        ret = wb_child_request_recv(subreq, talloc_tos(), &response, &err);
309
 
        TALLOC_FREE(subreq);
310
 
        if (ret == -1) {
311
 
                tevent_req_error(req, err);
312
 
                return;
313
 
        }
314
 
 
315
 
        if (!string_to_sid(&state->domain->sid,
316
 
                           response->data.domain_info.sid)) {
317
 
                DEBUG(1,("init_child_recv: Could not convert sid %s "
318
 
                        "from string\n", response->data.domain_info.sid));
319
 
                tevent_req_error(req, EINVAL);
320
 
                return;
321
 
        }
322
 
        fstrcpy(state->domain->name, response->data.domain_info.name);
323
 
        fstrcpy(state->domain->alt_name, response->data.domain_info.alt_name);
324
 
        state->domain->native_mode = response->data.domain_info.native_mode;
325
 
        state->domain->active_directory =
326
 
                response->data.domain_info.active_directory;
327
 
        state->domain->initialized = true;
328
 
 
329
 
        TALLOC_FREE(response);
330
 
 
331
 
        subreq = wb_child_request_send(state, state->ev, &state->domain->child,
332
 
                                       state->request);
333
 
        if (tevent_req_nomem(subreq, req)) {
334
 
                return;
335
 
        }
336
 
        tevent_req_set_callback(subreq, wb_domain_request_done, req);
337
 
}
338
 
 
339
 
static void wb_domain_request_done(struct tevent_req *subreq)
340
 
{
341
 
        struct tevent_req *req = tevent_req_callback_data(
342
 
                subreq, struct tevent_req);
343
 
        struct wb_domain_request_state *state = tevent_req_data(
344
 
                req, struct wb_domain_request_state);
345
 
        int ret, err;
346
 
 
347
 
        ret = wb_child_request_recv(subreq, talloc_tos(), &state->response,
348
 
                                    &err);
349
 
        TALLOC_FREE(subreq);
350
 
        if (ret == -1) {
351
 
                tevent_req_error(req, err);
352
 
                return;
353
 
        }
354
 
        tevent_req_done(req);
355
 
}
356
 
 
357
 
int wb_domain_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
358
 
                           struct winbindd_response **presponse, int *err)
359
 
{
360
 
        struct wb_domain_request_state *state = tevent_req_data(
361
 
                req, struct wb_domain_request_state);
362
 
 
363
 
        if (tevent_req_is_unix_error(req, err)) {
364
 
                return -1;
365
 
        }
366
 
        *presponse = talloc_move(mem_ctx, &state->response);
367
 
        return 0;
368
 
}
369
 
 
370
 
struct domain_request_state {
371
 
        struct winbindd_domain *domain;
372
 
        struct winbindd_request *request;
373
 
        struct winbindd_response *response;
374
 
        void (*continuation)(void *private_data_data, bool success);
375
 
        void *private_data_data;
376
 
};
377
 
 
378
 
static void async_domain_request_done(struct tevent_req *req);
379
 
 
380
 
void async_domain_request(TALLOC_CTX *mem_ctx,
381
 
                          struct winbindd_domain *domain,
382
 
                          struct winbindd_request *request,
383
 
                          struct winbindd_response *response,
384
 
                          void (*continuation)(void *private_data_data, bool success),
385
 
                          void *private_data_data)
386
 
{
387
 
        struct tevent_req *subreq;
388
 
        struct domain_request_state *state;
389
 
 
390
 
        state = TALLOC_P(mem_ctx, struct domain_request_state);
391
 
        if (state == NULL) {
392
 
                DEBUG(0, ("talloc failed\n"));
393
 
                continuation(private_data_data, False);
394
 
                return;
395
 
        }
396
 
 
397
 
        state->domain = domain;
398
 
        state->request = request;
399
 
        state->response = response;
400
 
        state->continuation = continuation;
401
 
        state->private_data_data = private_data_data;
402
 
 
403
 
        subreq = wb_domain_request_send(state, winbind_event_context(),
404
 
                                        domain, request);
405
 
        if (subreq == NULL) {
406
 
                DEBUG(5, ("wb_domain_request_send failed\n"));
407
 
                continuation(private_data_data, false);
408
 
                return;
409
 
        }
410
 
        tevent_req_set_callback(subreq, async_domain_request_done, state);
411
 
}
412
 
 
413
 
static void async_domain_request_done(struct tevent_req *req)
414
 
{
415
 
        struct domain_request_state *state = tevent_req_callback_data(
416
 
                req, struct domain_request_state);
417
 
        struct winbindd_response *response;
418
 
        int ret, err;
419
 
 
420
 
        ret = wb_domain_request_recv(req, state, &response, &err);
421
 
        TALLOC_FREE(req);
422
 
        if (ret == -1) {
423
 
                DEBUG(5, ("wb_domain_request returned %s\n", strerror(err)));
424
 
                state->continuation(state->private_data_data, false);
425
 
                return;
426
 
        }
427
 
        *(state->response) = *response;
428
 
        state->continuation(state->private_data_data, true);
429
 
}
430
 
 
431
 
static void recvfrom_child(void *private_data_data, bool success)
432
 
{
433
 
        struct winbindd_cli_state *state =
434
 
                talloc_get_type_abort(private_data_data, struct winbindd_cli_state);
435
 
        enum winbindd_result result = state->response->result;
436
 
 
437
 
        /* This is an optimization: The child has written directly to the
438
 
         * response buffer. The request itself is still in pending state,
439
 
         * state that in the result code. */
440
 
 
441
 
        state->response->result = WINBINDD_PENDING;
442
 
 
443
 
        if ((!success) || (result != WINBINDD_OK)) {
444
 
                request_error(state);
445
 
                return;
446
 
        }
447
 
 
448
 
        request_ok(state);
449
 
}
450
 
 
451
 
void sendto_domain(struct winbindd_cli_state *state,
452
 
                   struct winbindd_domain *domain)
453
 
{
454
 
        async_domain_request(state->mem_ctx, domain,
455
 
                             state->request, state->response,
456
 
                             recvfrom_child, state);
457
 
}
458
 
 
459
 
static void child_process_request(struct winbindd_child *child,
460
 
                                  struct winbindd_cli_state *state)
461
 
{
462
 
        struct winbindd_domain *domain = child->domain;
463
 
        const struct winbindd_child_dispatch_table *table = child->table;
464
 
 
465
 
        /* Free response data - we may be interrupted and receive another
466
 
           command before being able to send this data off. */
467
 
 
468
 
        state->response->result = WINBINDD_ERROR;
469
 
        state->response->length = sizeof(struct winbindd_response);
470
 
 
471
 
        /* as all requests in the child are sync, we can use talloc_tos() */
472
 
        state->mem_ctx = talloc_tos();
473
 
 
474
 
        /* Process command */
475
 
 
476
 
        for (; table->name; table++) {
477
 
                if (state->request->cmd == table->struct_cmd) {
478
 
                        DEBUG(10,("child_process_request: request fn %s\n",
479
 
                                  table->name));
480
 
                        state->response->result = table->struct_fn(domain, state);
481
 
                        return;
482
 
                }
483
 
        }
484
 
 
485
 
        DEBUG(1 ,("child_process_request: unknown request fn number %d\n",
486
 
                  (int)state->request->cmd));
487
 
        state->response->result = WINBINDD_ERROR;
488
 
}
489
 
 
490
 
void setup_child(struct winbindd_domain *domain, struct winbindd_child *child,
491
 
                 const struct winbindd_child_dispatch_table *table,
492
 
                 const char *logprefix,
493
 
                 const char *logname)
494
 
{
495
 
        if (logprefix && logname) {
496
 
                if (asprintf(&child->logfilename, "%s/%s-%s",
497
 
                             get_dyn_LOGFILEBASE(), logprefix, logname) < 0) {
498
 
                        smb_panic("Internal error: asprintf failed");
499
 
                }
500
 
        } else {
501
 
                smb_panic("Internal error: logprefix == NULL && "
502
 
                          "logname == NULL");
503
 
        }
504
 
 
505
 
        child->domain = domain;
506
 
        child->table = table;
507
 
        child->queue = tevent_queue_create(NULL, "winbind_child");
508
 
        SMB_ASSERT(child->queue != NULL);
509
 
        child->rpccli = wbint_rpccli_create(NULL, domain, child);
510
 
        SMB_ASSERT(child->rpccli != NULL);
511
 
}
512
 
 
513
 
struct winbindd_child *children = NULL;
514
 
 
515
 
void winbind_child_died(pid_t pid)
516
 
{
517
 
        struct winbindd_child *child;
518
 
 
519
 
        for (child = children; child != NULL; child = child->next) {
520
 
                if (child->pid == pid) {
521
 
                        break;
522
 
                }
523
 
        }
524
 
 
525
 
        if (child == NULL) {
526
 
                DEBUG(5, ("Already reaped child %u died\n", (unsigned int)pid));
527
 
                return;
528
 
        }
529
 
 
530
 
        /* This will be re-added in fork_domain_child() */
531
 
 
532
 
        DLIST_REMOVE(children, child);
533
 
 
534
 
        close(child->sock);
535
 
        child->sock = -1;
536
 
        child->pid = 0;
537
 
}
538
 
 
539
 
/* Ensure any negative cache entries with the netbios or realm names are removed. */
540
 
 
541
 
void winbindd_flush_negative_conn_cache(struct winbindd_domain *domain)
542
 
{
543
 
        flush_negative_conn_cache_for_domain(domain->name);
544
 
        if (*domain->alt_name) {
545
 
                flush_negative_conn_cache_for_domain(domain->alt_name);
546
 
        }
547
 
}
548
 
 
549
 
/* 
550
 
 * Parent winbindd process sets its own debug level first and then
551
 
 * sends a message to all the winbindd children to adjust their debug
552
 
 * level to that of parents.
553
 
 */
554
 
 
555
 
void winbind_msg_debug(struct messaging_context *msg_ctx,
556
 
                         void *private_data,
557
 
                         uint32_t msg_type,
558
 
                         struct server_id server_id,
559
 
                         DATA_BLOB *data)
560
 
{
561
 
        struct winbindd_child *child;
562
 
 
563
 
        DEBUG(10,("winbind_msg_debug: got debug message.\n"));
564
 
 
565
 
        debug_message(msg_ctx, private_data, MSG_DEBUG, server_id, data);
566
 
 
567
 
        for (child = children; child != NULL; child = child->next) {
568
 
 
569
 
                DEBUG(10,("winbind_msg_debug: sending message to pid %u.\n",
570
 
                        (unsigned int)child->pid));
571
 
 
572
 
                messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
573
 
                           MSG_DEBUG,
574
 
                           data->data,
575
 
                           strlen((char *) data->data) + 1);
576
 
        }
577
 
}
578
 
 
579
 
/* Set our domains as offline and forward the offline message to our children. */
580
 
 
581
 
void winbind_msg_offline(struct messaging_context *msg_ctx,
582
 
                         void *private_data,
583
 
                         uint32_t msg_type,
584
 
                         struct server_id server_id,
585
 
                         DATA_BLOB *data)
586
 
{
587
 
        struct winbindd_child *child;
588
 
        struct winbindd_domain *domain;
589
 
 
590
 
        DEBUG(10,("winbind_msg_offline: got offline message.\n"));
591
 
 
592
 
        if (!lp_winbind_offline_logon()) {
593
 
                DEBUG(10,("winbind_msg_offline: rejecting offline message.\n"));
594
 
                return;
595
 
        }
596
 
 
597
 
        /* Set our global state as offline. */
598
 
        if (!set_global_winbindd_state_offline()) {
599
 
                DEBUG(10,("winbind_msg_offline: offline request failed.\n"));
600
 
                return;
601
 
        }
602
 
 
603
 
        /* Set all our domains as offline. */
604
 
        for (domain = domain_list(); domain; domain = domain->next) {
605
 
                if (domain->internal) {
606
 
                        continue;
607
 
                }
608
 
                DEBUG(5,("winbind_msg_offline: marking %s offline.\n", domain->name));
609
 
                set_domain_offline(domain);
610
 
        }
611
 
 
612
 
        for (child = children; child != NULL; child = child->next) {
613
 
                /* Don't send message to internal childs.  We've already
614
 
                   done so above. */
615
 
                if (!child->domain || winbindd_internal_child(child)) {
616
 
                        continue;
617
 
                }
618
 
 
619
 
                /* Or internal domains (this should not be possible....) */
620
 
                if (child->domain->internal) {
621
 
                        continue;
622
 
                }
623
 
 
624
 
                /* Each winbindd child should only process requests for one domain - make sure
625
 
                   we only set it online / offline for that domain. */
626
 
 
627
 
                DEBUG(10,("winbind_msg_offline: sending message to pid %u for domain %s.\n",
628
 
                        (unsigned int)child->pid, domain->name ));
629
 
 
630
 
                messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
631
 
                                   MSG_WINBIND_OFFLINE,
632
 
                                   (uint8 *)child->domain->name,
633
 
                                   strlen(child->domain->name)+1);
634
 
        }
635
 
}
636
 
 
637
 
/* Set our domains as online and forward the online message to our children. */
638
 
 
639
 
void winbind_msg_online(struct messaging_context *msg_ctx,
640
 
                        void *private_data,
641
 
                        uint32_t msg_type,
642
 
                        struct server_id server_id,
643
 
                        DATA_BLOB *data)
644
 
{
645
 
        struct winbindd_child *child;
646
 
        struct winbindd_domain *domain;
647
 
 
648
 
        DEBUG(10,("winbind_msg_online: got online message.\n"));
649
 
 
650
 
        if (!lp_winbind_offline_logon()) {
651
 
                DEBUG(10,("winbind_msg_online: rejecting online message.\n"));
652
 
                return;
653
 
        }
654
 
 
655
 
        /* Set our global state as online. */
656
 
        set_global_winbindd_state_online();
657
 
 
658
 
        smb_nscd_flush_user_cache();
659
 
        smb_nscd_flush_group_cache();
660
 
 
661
 
        /* Set all our domains as online. */
662
 
        for (domain = domain_list(); domain; domain = domain->next) {
663
 
                if (domain->internal) {
664
 
                        continue;
665
 
                }
666
 
                DEBUG(5,("winbind_msg_online: requesting %s to go online.\n", domain->name));
667
 
 
668
 
                winbindd_flush_negative_conn_cache(domain);
669
 
                set_domain_online_request(domain);
670
 
 
671
 
                /* Send an online message to the idmap child when our
672
 
                   primary domain comes back online */
673
 
 
674
 
                if ( domain->primary ) {
675
 
                        struct winbindd_child *idmap = idmap_child();
676
 
 
677
 
                        if ( idmap->pid != 0 ) {
678
 
                                messaging_send_buf(msg_ctx,
679
 
                                                   pid_to_procid(idmap->pid), 
680
 
                                                   MSG_WINBIND_ONLINE,
681
 
                                                   (uint8 *)domain->name,
682
 
                                                   strlen(domain->name)+1);
683
 
                        }
684
 
                }
685
 
        }
686
 
 
687
 
        for (child = children; child != NULL; child = child->next) {
688
 
                /* Don't send message to internal childs. */
689
 
                if (!child->domain || winbindd_internal_child(child)) {
690
 
                        continue;
691
 
                }
692
 
 
693
 
                /* Or internal domains (this should not be possible....) */
694
 
                if (child->domain->internal) {
695
 
                        continue;
696
 
                }
697
 
 
698
 
                /* Each winbindd child should only process requests for one domain - make sure
699
 
                   we only set it online / offline for that domain. */
700
 
 
701
 
                DEBUG(10,("winbind_msg_online: sending message to pid %u for domain %s.\n",
702
 
                        (unsigned int)child->pid, child->domain->name ));
703
 
 
704
 
                messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
705
 
                                   MSG_WINBIND_ONLINE,
706
 
                                   (uint8 *)child->domain->name,
707
 
                                   strlen(child->domain->name)+1);
708
 
        }
709
 
}
710
 
 
711
 
static const char *collect_onlinestatus(TALLOC_CTX *mem_ctx)
712
 
{
713
 
        struct winbindd_domain *domain;
714
 
        char *buf = NULL;
715
 
 
716
 
        if ((buf = talloc_asprintf(mem_ctx, "global:%s ", 
717
 
                                   get_global_winbindd_state_offline() ? 
718
 
                                   "Offline":"Online")) == NULL) {
719
 
                return NULL;
720
 
        }
721
 
 
722
 
        for (domain = domain_list(); domain; domain = domain->next) {
723
 
                if ((buf = talloc_asprintf_append_buffer(buf, "%s:%s ", 
724
 
                                                  domain->name, 
725
 
                                                  domain->online ?
726
 
                                                  "Online":"Offline")) == NULL) {
727
 
                        return NULL;
728
 
                }
729
 
        }
730
 
 
731
 
        buf = talloc_asprintf_append_buffer(buf, "\n");
732
 
 
733
 
        DEBUG(5,("collect_onlinestatus: %s", buf));
734
 
 
735
 
        return buf;
736
 
}
737
 
 
738
 
void winbind_msg_onlinestatus(struct messaging_context *msg_ctx,
739
 
                              void *private_data,
740
 
                              uint32_t msg_type,
741
 
                              struct server_id server_id,
742
 
                              DATA_BLOB *data)
743
 
{
744
 
        TALLOC_CTX *mem_ctx;
745
 
        const char *message;
746
 
        struct server_id *sender;
747
 
 
748
 
        DEBUG(5,("winbind_msg_onlinestatus received.\n"));
749
 
 
750
 
        if (!data->data) {
751
 
                return;
752
 
        }
753
 
 
754
 
        sender = (struct server_id *)data->data;
755
 
 
756
 
        mem_ctx = talloc_init("winbind_msg_onlinestatus");
757
 
        if (mem_ctx == NULL) {
758
 
                return;
759
 
        }
760
 
 
761
 
        message = collect_onlinestatus(mem_ctx);
762
 
        if (message == NULL) {
763
 
                talloc_destroy(mem_ctx);
764
 
                return;
765
 
        }
766
 
 
767
 
        messaging_send_buf(msg_ctx, *sender, MSG_WINBIND_ONLINESTATUS, 
768
 
                           (uint8 *)message, strlen(message) + 1);
769
 
 
770
 
        talloc_destroy(mem_ctx);
771
 
}
772
 
 
773
 
void winbind_msg_dump_event_list(struct messaging_context *msg_ctx,
774
 
                                 void *private_data,
775
 
                                 uint32_t msg_type,
776
 
                                 struct server_id server_id,
777
 
                                 DATA_BLOB *data)
778
 
{
779
 
        struct winbindd_child *child;
780
 
 
781
 
        DEBUG(10,("winbind_msg_dump_event_list received\n"));
782
 
 
783
 
        dump_event_list(winbind_event_context());
784
 
 
785
 
        for (child = children; child != NULL; child = child->next) {
786
 
 
787
 
                DEBUG(10,("winbind_msg_dump_event_list: sending message to pid %u\n",
788
 
                        (unsigned int)child->pid));
789
 
 
790
 
                messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
791
 
                                   MSG_DUMP_EVENT_LIST,
792
 
                                   NULL, 0);
793
 
        }
794
 
 
795
 
}
796
 
 
797
 
void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx,
798
 
                                  void *private_data,
799
 
                                  uint32_t msg_type,
800
 
                                  struct server_id server_id,
801
 
                                  DATA_BLOB *data)
802
 
{
803
 
        TALLOC_CTX *mem_ctx;
804
 
        const char *message = NULL;
805
 
        struct server_id *sender = NULL;
806
 
        const char *domain = NULL;
807
 
        char *s = NULL;
808
 
        NTSTATUS status;
809
 
        struct winbindd_domain *dom = NULL;
810
 
 
811
 
        DEBUG(5,("winbind_msg_dump_domain_list received.\n"));
812
 
 
813
 
        if (!data || !data->data) {
814
 
                return;
815
 
        }
816
 
 
817
 
        if (data->length < sizeof(struct server_id)) {
818
 
                return;
819
 
        }
820
 
 
821
 
        mem_ctx = talloc_init("winbind_msg_dump_domain_list");
822
 
        if (!mem_ctx) {
823
 
                return;
824
 
        }
825
 
 
826
 
        sender = (struct server_id *)data->data;
827
 
        if (data->length > sizeof(struct server_id)) {
828
 
                domain = (const char *)data->data+sizeof(struct server_id);
829
 
        }
830
 
 
831
 
        if (domain) {
832
 
 
833
 
                DEBUG(5,("winbind_msg_dump_domain_list for domain: %s\n",
834
 
                        domain));
835
 
 
836
 
                message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain,
837
 
                                                  find_domain_from_name_noinit(domain));
838
 
                if (!message) {
839
 
                        talloc_destroy(mem_ctx);
840
 
                        return;
841
 
                }
842
 
 
843
 
                messaging_send_buf(msg_ctx, *sender,
844
 
                                   MSG_WINBIND_DUMP_DOMAIN_LIST,
845
 
                                   (uint8_t *)message, strlen(message) + 1);
846
 
 
847
 
                talloc_destroy(mem_ctx);
848
 
 
849
 
                return;
850
 
        }
851
 
 
852
 
        DEBUG(5,("winbind_msg_dump_domain_list all domains\n"));
853
 
 
854
 
        for (dom = domain_list(); dom; dom=dom->next) {
855
 
                message = NDR_PRINT_STRUCT_STRING(mem_ctx, winbindd_domain, dom);
856
 
                if (!message) {
857
 
                        talloc_destroy(mem_ctx);
858
 
                        return;
859
 
                }
860
 
 
861
 
                s = talloc_asprintf_append(s, "%s\n", message);
862
 
                if (!s) {
863
 
                        talloc_destroy(mem_ctx);
864
 
                        return;
865
 
                }
866
 
        }
867
 
 
868
 
        status = messaging_send_buf(msg_ctx, *sender,
869
 
                                    MSG_WINBIND_DUMP_DOMAIN_LIST,
870
 
                                    (uint8_t *)s, strlen(s) + 1);
871
 
        if (!NT_STATUS_IS_OK(status)) {
872
 
                DEBUG(0,("failed to send message: %s\n",
873
 
                nt_errstr(status)));
874
 
        }
875
 
 
876
 
        talloc_destroy(mem_ctx);
877
 
}
878
 
 
879
 
static void account_lockout_policy_handler(struct event_context *ctx,
880
 
                                           struct timed_event *te,
881
 
                                           struct timeval now,
882
 
                                           void *private_data)
883
 
{
884
 
        struct winbindd_child *child =
885
 
                (struct winbindd_child *)private_data;
886
 
        TALLOC_CTX *mem_ctx = NULL;
887
 
        struct winbindd_methods *methods;
888
 
        struct samr_DomInfo12 lockout_policy;
889
 
        NTSTATUS result;
890
 
 
891
 
        DEBUG(10,("account_lockout_policy_handler called\n"));
892
 
 
893
 
        TALLOC_FREE(child->lockout_policy_event);
894
 
 
895
 
        if ( !winbindd_can_contact_domain( child->domain ) ) {
896
 
                DEBUG(10,("account_lockout_policy_handler: Removing myself since I "
897
 
                          "do not have an incoming trust to domain %s\n", 
898
 
                          child->domain->name));
899
 
 
900
 
                return;         
901
 
        }
902
 
 
903
 
        methods = child->domain->methods;
904
 
 
905
 
        mem_ctx = talloc_init("account_lockout_policy_handler ctx");
906
 
        if (!mem_ctx) {
907
 
                result = NT_STATUS_NO_MEMORY;
908
 
        } else {
909
 
                result = methods->lockout_policy(child->domain, mem_ctx, &lockout_policy);
910
 
        }
911
 
        TALLOC_FREE(mem_ctx);
912
 
 
913
 
        if (!NT_STATUS_IS_OK(result)) {
914
 
                DEBUG(10,("account_lockout_policy_handler: lockout_policy failed error %s\n",
915
 
                         nt_errstr(result)));
916
 
        }
917
 
 
918
 
        child->lockout_policy_event = event_add_timed(winbind_event_context(), NULL,
919
 
                                                      timeval_current_ofs(3600, 0),
920
 
                                                      account_lockout_policy_handler,
921
 
                                                      child);
922
 
}
923
 
 
924
 
static time_t get_machine_password_timeout(void)
925
 
{
926
 
        /* until we have gpo support use lp setting */
927
 
        return lp_machine_password_timeout();
928
 
}
929
 
 
930
 
static bool calculate_next_machine_pwd_change(const char *domain,
931
 
                                              struct timeval *t)
932
 
{
933
 
        time_t pass_last_set_time;
934
 
        time_t timeout;
935
 
        time_t next_change;
936
 
        struct timeval tv;
937
 
        char *pw;
938
 
 
939
 
        pw = secrets_fetch_machine_password(domain,
940
 
                                            &pass_last_set_time,
941
 
                                            NULL);
942
 
 
943
 
        if (pw == NULL) {
944
 
                DEBUG(0,("cannot fetch own machine password ????"));
945
 
                return false;
946
 
        }
947
 
 
948
 
        SAFE_FREE(pw);
949
 
 
950
 
        timeout = get_machine_password_timeout();
951
 
        if (timeout == 0) {
952
 
                DEBUG(10,("machine password never expires\n"));
953
 
                return false;
954
 
        }
955
 
 
956
 
        tv.tv_sec = pass_last_set_time;
957
 
        DEBUG(10, ("password last changed %s\n",
958
 
                   timeval_string(talloc_tos(), &tv, false)));
959
 
        tv.tv_sec += timeout;
960
 
        DEBUGADD(10, ("password valid until %s\n",
961
 
                      timeval_string(talloc_tos(), &tv, false)));
962
 
 
963
 
        if (time(NULL) < (pass_last_set_time + timeout)) {
964
 
                next_change = pass_last_set_time + timeout;
965
 
                DEBUG(10,("machine password still valid until: %s\n",
966
 
                        http_timestring(talloc_tos(), next_change)));
967
 
                *t = timeval_set(next_change, 0);
968
 
 
969
 
                if (lp_clustering()) {
970
 
                        uint8_t randbuf;
971
 
                        /*
972
 
                         * When having a cluster, we have several
973
 
                         * winbinds racing for the password change. In
974
 
                         * the machine_password_change_handler()
975
 
                         * function we check if someone else was
976
 
                         * faster when the event triggers. We add a
977
 
                         * 255-second random delay here, so that we
978
 
                         * don't run to change the password at the
979
 
                         * exact same moment.
980
 
                         */
981
 
                        generate_random_buffer(&randbuf, sizeof(randbuf));
982
 
                        DEBUG(10, ("adding %d seconds randomness\n",
983
 
                                   (int)randbuf));
984
 
                        t->tv_sec += randbuf;
985
 
                }
986
 
                return true;
987
 
        }
988
 
 
989
 
        DEBUG(10,("machine password expired, needs immediate change\n"));
990
 
 
991
 
        *t = timeval_zero();
992
 
 
993
 
        return true;
994
 
}
995
 
 
996
 
static void machine_password_change_handler(struct event_context *ctx,
997
 
                                            struct timed_event *te,
998
 
                                            struct timeval now,
999
 
                                            void *private_data)
1000
 
{
1001
 
        struct winbindd_child *child =
1002
 
                (struct winbindd_child *)private_data;
1003
 
        struct rpc_pipe_client *netlogon_pipe = NULL;
1004
 
        TALLOC_CTX *frame;
1005
 
        NTSTATUS result;
1006
 
        struct timeval next_change;
1007
 
 
1008
 
        DEBUG(10,("machine_password_change_handler called\n"));
1009
 
 
1010
 
        TALLOC_FREE(child->machine_password_change_event);
1011
 
 
1012
 
        if (!calculate_next_machine_pwd_change(child->domain->name,
1013
 
                                               &next_change)) {
1014
 
                DEBUG(10, ("calculate_next_machine_pwd_change failed\n"));
1015
 
                return;
1016
 
        }
1017
 
 
1018
 
        DEBUG(10, ("calculate_next_machine_pwd_change returned %s\n",
1019
 
                   timeval_string(talloc_tos(), &next_change, false)));
1020
 
 
1021
 
        if (!timeval_expired(&next_change)) {
1022
 
                DEBUG(10, ("Someone else has already changed the pw\n"));
1023
 
                goto done;
1024
 
        }
1025
 
 
1026
 
        if (!winbindd_can_contact_domain(child->domain)) {
1027
 
                DEBUG(10,("machine_password_change_handler: Removing myself since I "
1028
 
                          "do not have an incoming trust to domain %s\n",
1029
 
                          child->domain->name));
1030
 
                return;
1031
 
        }
1032
 
 
1033
 
        result = cm_connect_netlogon(child->domain, &netlogon_pipe);
1034
 
        if (!NT_STATUS_IS_OK(result)) {
1035
 
                DEBUG(10,("machine_password_change_handler: "
1036
 
                        "failed to connect netlogon pipe: %s\n",
1037
 
                         nt_errstr(result)));
1038
 
                return;
1039
 
        }
1040
 
 
1041
 
        frame = talloc_stackframe();
1042
 
 
1043
 
        result = trust_pw_find_change_and_store_it(netlogon_pipe,
1044
 
                                                   frame,
1045
 
                                                   child->domain->name);
1046
 
        TALLOC_FREE(frame);
1047
 
 
1048
 
        DEBUG(10, ("machine_password_change_handler: "
1049
 
                   "trust_pw_find_change_and_store_it returned %s\n",
1050
 
                   nt_errstr(result)));
1051
 
 
1052
 
        if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1053
 
                DEBUG(3,("machine_password_change_handler: password set returned "
1054
 
                         "ACCESS_DENIED.  Maybe the trust account "
1055
 
                         "password was changed and we didn't know it. "
1056
 
                         "Killing connections to domain %s\n",
1057
 
                         child->domain->name));
1058
 
                TALLOC_FREE(child->domain->conn.netlogon_pipe);
1059
 
        }
1060
 
 
1061
 
        if (!calculate_next_machine_pwd_change(child->domain->name,
1062
 
                                               &next_change)) {
1063
 
                DEBUG(10, ("calculate_next_machine_pwd_change failed\n"));
1064
 
                return;
1065
 
        }
1066
 
 
1067
 
        DEBUG(10, ("calculate_next_machine_pwd_change returned %s\n",
1068
 
                   timeval_string(talloc_tos(), &next_change, false)));
1069
 
 
1070
 
        if (!NT_STATUS_IS_OK(result)) {
1071
 
                struct timeval tmp;
1072
 
                /*
1073
 
                 * In case of failure, give the DC a minute to recover
1074
 
                 */
1075
 
                tmp = timeval_current_ofs(60, 0);
1076
 
                next_change = timeval_max(&next_change, &tmp);
1077
 
        }
1078
 
 
1079
 
done:
1080
 
        child->machine_password_change_event = event_add_timed(winbind_event_context(), NULL,
1081
 
                                                              next_change,
1082
 
                                                              machine_password_change_handler,
1083
 
                                                              child);
1084
 
}
1085
 
 
1086
 
/* Deal with a request to go offline. */
1087
 
 
1088
 
static void child_msg_offline(struct messaging_context *msg,
1089
 
                              void *private_data,
1090
 
                              uint32_t msg_type,
1091
 
                              struct server_id server_id,
1092
 
                              DATA_BLOB *data)
1093
 
{
1094
 
        struct winbindd_domain *domain;
1095
 
        struct winbindd_domain *primary_domain = NULL;
1096
 
        const char *domainname = (const char *)data->data;
1097
 
 
1098
 
        if (data->data == NULL || data->length == 0) {
1099
 
                return;
1100
 
        }
1101
 
 
1102
 
        DEBUG(5,("child_msg_offline received for domain %s.\n", domainname));
1103
 
 
1104
 
        if (!lp_winbind_offline_logon()) {
1105
 
                DEBUG(10,("child_msg_offline: rejecting offline message.\n"));
1106
 
                return;
1107
 
        }
1108
 
 
1109
 
        primary_domain = find_our_domain();
1110
 
 
1111
 
        /* Mark the requested domain offline. */
1112
 
 
1113
 
        for (domain = domain_list(); domain; domain = domain->next) {
1114
 
                if (domain->internal) {
1115
 
                        continue;
1116
 
                }
1117
 
                if (strequal(domain->name, domainname)) {
1118
 
                        DEBUG(5,("child_msg_offline: marking %s offline.\n", domain->name));
1119
 
                        set_domain_offline(domain);
1120
 
                        /* we are in the trusted domain, set the primary domain 
1121
 
                         * offline too */
1122
 
                        if (domain != primary_domain) {
1123
 
                                set_domain_offline(primary_domain);
1124
 
                        }
1125
 
                }
1126
 
        }
1127
 
}
1128
 
 
1129
 
/* Deal with a request to go online. */
1130
 
 
1131
 
static void child_msg_online(struct messaging_context *msg,
1132
 
                             void *private_data,
1133
 
                             uint32_t msg_type,
1134
 
                             struct server_id server_id,
1135
 
                             DATA_BLOB *data)
1136
 
{
1137
 
        struct winbindd_domain *domain;
1138
 
        struct winbindd_domain *primary_domain = NULL;
1139
 
        const char *domainname = (const char *)data->data;
1140
 
 
1141
 
        if (data->data == NULL || data->length == 0) {
1142
 
                return;
1143
 
        }
1144
 
 
1145
 
        DEBUG(5,("child_msg_online received for domain %s.\n", domainname));
1146
 
 
1147
 
        if (!lp_winbind_offline_logon()) {
1148
 
                DEBUG(10,("child_msg_online: rejecting online message.\n"));
1149
 
                return;
1150
 
        }
1151
 
 
1152
 
        primary_domain = find_our_domain();
1153
 
 
1154
 
        /* Set our global state as online. */
1155
 
        set_global_winbindd_state_online();
1156
 
 
1157
 
        /* Try and mark everything online - delete any negative cache entries
1158
 
           to force a reconnect now. */
1159
 
 
1160
 
        for (domain = domain_list(); domain; domain = domain->next) {
1161
 
                if (domain->internal) {
1162
 
                        continue;
1163
 
                }
1164
 
                if (strequal(domain->name, domainname)) {
1165
 
                        DEBUG(5,("child_msg_online: requesting %s to go online.\n", domain->name));
1166
 
                        winbindd_flush_negative_conn_cache(domain);
1167
 
                        set_domain_online_request(domain);
1168
 
 
1169
 
                        /* we can be in trusted domain, which will contact primary domain
1170
 
                         * we have to bring primary domain online in trusted domain process
1171
 
                         * see, winbindd_dual_pam_auth() --> winbindd_dual_pam_auth_samlogon()
1172
 
                         * --> contact_domain = find_our_domain()
1173
 
                         * */
1174
 
                        if (domain != primary_domain) {
1175
 
                                winbindd_flush_negative_conn_cache(primary_domain);
1176
 
                                set_domain_online_request(primary_domain);
1177
 
                        }
1178
 
                }
1179
 
        }
1180
 
}
1181
 
 
1182
 
static void child_msg_dump_event_list(struct messaging_context *msg,
1183
 
                                      void *private_data,
1184
 
                                      uint32_t msg_type,
1185
 
                                      struct server_id server_id,
1186
 
                                      DATA_BLOB *data)
1187
 
{
1188
 
        DEBUG(5,("child_msg_dump_event_list received\n"));
1189
 
 
1190
 
        dump_event_list(winbind_event_context());
1191
 
}
1192
 
 
1193
 
bool winbindd_reinit_after_fork(const char *logfilename)
1194
 
{
1195
 
        struct winbindd_domain *domain;
1196
 
        struct winbindd_child *cl;
1197
 
 
1198
 
        if (!NT_STATUS_IS_OK(reinit_after_fork(winbind_messaging_context(),
1199
 
                                               winbind_event_context(),
1200
 
                                               true))) {
1201
 
                DEBUG(0,("reinit_after_fork() failed\n"));
1202
 
                return false;
1203
 
        }
1204
 
 
1205
 
        close_conns_after_fork();
1206
 
 
1207
 
        if (!override_logfile && logfilename) {
1208
 
                lp_set_logfile(logfilename);
1209
 
                reopen_logs();
1210
 
        }
1211
 
 
1212
 
        if (!winbindd_setup_sig_term_handler(false))
1213
 
                return false;
1214
 
        if (!winbindd_setup_sig_hup_handler(override_logfile ? NULL :
1215
 
                                            logfilename))
1216
 
                return false;
1217
 
 
1218
 
        /* Stop zombies in children */
1219
 
        CatchChild();
1220
 
 
1221
 
        /* Don't handle the same messages as our parent. */
1222
 
        messaging_deregister(winbind_messaging_context(),
1223
 
                             MSG_SMB_CONF_UPDATED, NULL);
1224
 
        messaging_deregister(winbind_messaging_context(),
1225
 
                             MSG_SHUTDOWN, NULL);
1226
 
        messaging_deregister(winbind_messaging_context(),
1227
 
                             MSG_WINBIND_OFFLINE, NULL);
1228
 
        messaging_deregister(winbind_messaging_context(),
1229
 
                             MSG_WINBIND_ONLINE, NULL);
1230
 
        messaging_deregister(winbind_messaging_context(),
1231
 
                             MSG_WINBIND_ONLINESTATUS, NULL);
1232
 
        messaging_deregister(winbind_messaging_context(),
1233
 
                             MSG_DUMP_EVENT_LIST, NULL);
1234
 
        messaging_deregister(winbind_messaging_context(),
1235
 
                             MSG_WINBIND_DUMP_DOMAIN_LIST, NULL);
1236
 
        messaging_deregister(winbind_messaging_context(),
1237
 
                             MSG_DEBUG, NULL);
1238
 
 
1239
 
        /* We have destroyed all events in the winbindd_event_context
1240
 
         * in reinit_after_fork(), so clean out all possible pending
1241
 
         * event pointers. */
1242
 
 
1243
 
        /* Deal with check_online_events. */
1244
 
 
1245
 
        for (domain = domain_list(); domain; domain = domain->next) {
1246
 
                TALLOC_FREE(domain->check_online_event);
1247
 
        }
1248
 
 
1249
 
        /* Ensure we're not handling a credential cache event inherited
1250
 
         * from our parent. */
1251
 
 
1252
 
        ccache_remove_all_after_fork();
1253
 
 
1254
 
        /* Destroy all possible events in child list. */
1255
 
        for (cl = children; cl != NULL; cl = cl->next) {
1256
 
                TALLOC_FREE(cl->lockout_policy_event);
1257
 
                TALLOC_FREE(cl->machine_password_change_event);
1258
 
 
1259
 
                /* Children should never be able to send
1260
 
                 * each other messages, all messages must
1261
 
                 * go through the parent.
1262
 
                 */
1263
 
                cl->pid = (pid_t)0;
1264
 
        }
1265
 
        /*
1266
 
         * This is a little tricky, children must not
1267
 
         * send an MSG_WINBIND_ONLINE message to idmap_child().
1268
 
         * If we are in a child of our primary domain or
1269
 
         * in the process created by fork_child_dc_connect(),
1270
 
         * and the primary domain cannot go online,
1271
 
         * fork_child_dc_connection() sends MSG_WINBIND_ONLINE
1272
 
         * periodically to idmap_child().
1273
 
         *
1274
 
         * The sequence is, fork_child_dc_connect() ---> getdcs() --->
1275
 
         * get_dc_name_via_netlogon() ---> cm_connect_netlogon()
1276
 
         * ---> init_dc_connection() ---> cm_open_connection --->
1277
 
         * set_domain_online(), sends MSG_WINBIND_ONLINE to
1278
 
         * idmap_child(). Disallow children sending messages
1279
 
         * to each other, all messages must go through the parent.
1280
 
         */
1281
 
        cl = idmap_child();
1282
 
        cl->pid = (pid_t)0;
1283
 
 
1284
 
        return true;
1285
 
}
1286
 
 
1287
 
/*
1288
 
 * In a child there will be only one domain, reference that here.
1289
 
 */
1290
 
static struct winbindd_domain *child_domain;
1291
 
 
1292
 
struct winbindd_domain *wb_child_domain(void)
1293
 
{
1294
 
        return child_domain;
1295
 
}
1296
 
 
1297
 
static bool fork_domain_child(struct winbindd_child *child)
1298
 
{
1299
 
        int fdpair[2];
1300
 
        struct winbindd_cli_state state;
1301
 
        struct winbindd_request request;
1302
 
        struct winbindd_response response;
1303
 
        struct winbindd_domain *primary_domain = NULL;
1304
 
 
1305
 
        if (child->domain) {
1306
 
                DEBUG(10, ("fork_domain_child called for domain '%s'\n",
1307
 
                           child->domain->name));
1308
 
        } else {
1309
 
                DEBUG(10, ("fork_domain_child called without domain.\n"));
1310
 
        }
1311
 
        child_domain = child->domain;
1312
 
 
1313
 
        if (socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair) != 0) {
1314
 
                DEBUG(0, ("Could not open child pipe: %s\n",
1315
 
                          strerror(errno)));
1316
 
                return False;
1317
 
        }
1318
 
 
1319
 
        ZERO_STRUCT(state);
1320
 
        state.pid = sys_getpid();
1321
 
        state.request = &request;
1322
 
        state.response = &response;
1323
 
 
1324
 
        child->pid = sys_fork();
1325
 
 
1326
 
        if (child->pid == -1) {
1327
 
                DEBUG(0, ("Could not fork: %s\n", strerror(errno)));
1328
 
                return False;
1329
 
        }
1330
 
 
1331
 
        if (child->pid != 0) {
1332
 
                /* Parent */
1333
 
                close(fdpair[0]);
1334
 
                child->next = child->prev = NULL;
1335
 
                DLIST_ADD(children, child);
1336
 
                child->sock = fdpair[1];
1337
 
                return True;
1338
 
        }
1339
 
 
1340
 
        /* Child */
1341
 
 
1342
 
        DEBUG(10, ("Child process %d\n", (int)sys_getpid()));
1343
 
 
1344
 
        state.sock = fdpair[0];
1345
 
        close(fdpair[1]);
1346
 
 
1347
 
        if (!winbindd_reinit_after_fork(child->logfilename)) {
1348
 
                _exit(0);
1349
 
        }
1350
 
 
1351
 
        /* Handle online/offline messages. */
1352
 
        messaging_register(winbind_messaging_context(), NULL,
1353
 
                           MSG_WINBIND_OFFLINE, child_msg_offline);
1354
 
        messaging_register(winbind_messaging_context(), NULL,
1355
 
                           MSG_WINBIND_ONLINE, child_msg_online);
1356
 
        messaging_register(winbind_messaging_context(), NULL,
1357
 
                           MSG_DUMP_EVENT_LIST, child_msg_dump_event_list);
1358
 
        messaging_register(winbind_messaging_context(), NULL,
1359
 
                           MSG_DEBUG, debug_message);
1360
 
 
1361
 
        primary_domain = find_our_domain();
1362
 
 
1363
 
        if (primary_domain == NULL) {
1364
 
                smb_panic("no primary domain found");
1365
 
        }
1366
 
 
1367
 
        /* It doesn't matter if we allow cache login,
1368
 
         * try to bring domain online after fork. */
1369
 
        if ( child->domain ) {
1370
 
                child->domain->startup = True;
1371
 
                child->domain->startup_time = time(NULL);
1372
 
                /* we can be in primary domain or in trusted domain
1373
 
                 * If we are in trusted domain, set the primary domain
1374
 
                 * in start-up mode */
1375
 
                if (!(child->domain->internal)) {
1376
 
                        set_domain_online_request(child->domain);
1377
 
                        if (!(child->domain->primary)) {
1378
 
                                primary_domain->startup = True;
1379
 
                                primary_domain->startup_time = time(NULL);
1380
 
                                set_domain_online_request(primary_domain);
1381
 
                        }
1382
 
                }
1383
 
        }
1384
 
 
1385
 
        /*
1386
 
         * We are in idmap child, make sure that we set the
1387
 
         * check_online_event to bring primary domain online.
1388
 
         */
1389
 
        if (child == idmap_child()) {
1390
 
                set_domain_online_request(primary_domain);
1391
 
        }
1392
 
 
1393
 
        /* We might be in the idmap child...*/
1394
 
        if (child->domain && !(child->domain->internal) &&
1395
 
            lp_winbind_offline_logon()) {
1396
 
 
1397
 
                set_domain_online_request(child->domain);
1398
 
 
1399
 
                if (primary_domain && (primary_domain != child->domain)) {
1400
 
                        /* We need to talk to the primary
1401
 
                         * domain as well as the trusted
1402
 
                         * domain inside a trusted domain
1403
 
                         * child.
1404
 
                         * See the code in :
1405
 
                         * set_dc_type_and_flags_trustinfo()
1406
 
                         * for details.
1407
 
                         */
1408
 
                        set_domain_online_request(primary_domain);
1409
 
                }
1410
 
 
1411
 
                child->lockout_policy_event = event_add_timed(
1412
 
                        winbind_event_context(), NULL, timeval_zero(),
1413
 
                        account_lockout_policy_handler,
1414
 
                        child);
1415
 
        }
1416
 
 
1417
 
        if (child->domain && child->domain->primary &&
1418
 
            !USE_KERBEROS_KEYTAB &&
1419
 
            lp_server_role() == ROLE_DOMAIN_MEMBER) {
1420
 
 
1421
 
                struct timeval next_change;
1422
 
 
1423
 
                if (calculate_next_machine_pwd_change(child->domain->name,
1424
 
                                                       &next_change)) {
1425
 
                        child->machine_password_change_event = event_add_timed(
1426
 
                                winbind_event_context(), NULL, next_change,
1427
 
                                machine_password_change_handler,
1428
 
                                child);
1429
 
                }
1430
 
        }
1431
 
 
1432
 
        while (1) {
1433
 
 
1434
 
                int ret;
1435
 
                fd_set r_fds;
1436
 
                fd_set w_fds;
1437
 
                int maxfd;
1438
 
                struct timeval t;
1439
 
                struct timeval *tp;
1440
 
                struct timeval now;
1441
 
                TALLOC_CTX *frame = talloc_stackframe();
1442
 
                struct iovec iov[2];
1443
 
                int iov_count;
1444
 
                NTSTATUS status;
1445
 
 
1446
 
                if (run_events(winbind_event_context(), 0, NULL, NULL)) {
1447
 
                        TALLOC_FREE(frame);
1448
 
                        continue;
1449
 
                }
1450
 
 
1451
 
                GetTimeOfDay(&now);
1452
 
 
1453
 
                if (child->domain && child->domain->startup &&
1454
 
                                (now.tv_sec > child->domain->startup_time + 30)) {
1455
 
                        /* No longer in "startup" mode. */
1456
 
                        DEBUG(10,("fork_domain_child: domain %s no longer in 'startup' mode.\n",
1457
 
                                child->domain->name ));
1458
 
                        child->domain->startup = False;
1459
 
                }
1460
 
 
1461
 
                FD_ZERO(&r_fds);
1462
 
                FD_ZERO(&w_fds);
1463
 
                FD_SET(state.sock, &r_fds);
1464
 
                maxfd = state.sock;
1465
 
 
1466
 
                /*
1467
 
                 * Initialize this high as event_add_to_select_args()
1468
 
                 * uses a timeval_min() on this and next_event. Fix
1469
 
                 * from Roel van Meer <rolek@alt001.com>.
1470
 
                 */
1471
 
                t.tv_sec = 999999;
1472
 
                t.tv_usec = 0;
1473
 
 
1474
 
                event_add_to_select_args(winbind_event_context(), &now,
1475
 
                                         &r_fds, &w_fds, &t, &maxfd);
1476
 
                tp = get_timed_events_timeout(winbind_event_context(), &t);
1477
 
                if (tp) {
1478
 
                        DEBUG(11,("select will use timeout of %u.%u seconds\n",
1479
 
                                (unsigned int)tp->tv_sec, (unsigned int)tp->tv_usec ));
1480
 
                }
1481
 
 
1482
 
                ret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, tp);
1483
 
 
1484
 
                if (run_events(winbind_event_context(), ret, &r_fds, &w_fds)) {
1485
 
                        /* We got a signal - continue. */
1486
 
                        TALLOC_FREE(frame);
1487
 
                        continue;
1488
 
                }
1489
 
 
1490
 
                if (ret == 0) {
1491
 
                        DEBUG(11,("nothing is ready yet, continue\n"));
1492
 
                        TALLOC_FREE(frame);
1493
 
                        continue;
1494
 
                }
1495
 
 
1496
 
                if (ret == -1 && errno == EINTR) {
1497
 
                        /* We got a signal - continue. */
1498
 
                        TALLOC_FREE(frame);
1499
 
                        continue;
1500
 
                }
1501
 
 
1502
 
                if (ret == -1 && errno != EINTR) {
1503
 
                        DEBUG(0,("select error occured\n"));
1504
 
                        TALLOC_FREE(frame);
1505
 
                        perror("select");
1506
 
                        _exit(1);
1507
 
                }
1508
 
 
1509
 
                /* fetch a request from the main daemon */
1510
 
                status = child_read_request(&state);
1511
 
 
1512
 
                if (!NT_STATUS_IS_OK(status)) {
1513
 
                        /* we lost contact with our parent */
1514
 
                        _exit(0);
1515
 
                }
1516
 
 
1517
 
                DEBUG(4,("child daemon request %d\n", (int)state.request->cmd));
1518
 
 
1519
 
                ZERO_STRUCTP(state.response);
1520
 
                state.request->null_term = '\0';
1521
 
                state.mem_ctx = frame;
1522
 
                child_process_request(child, &state);
1523
 
 
1524
 
                DEBUG(4, ("Finished processing child request %d\n",
1525
 
                          (int)state.request->cmd));
1526
 
 
1527
 
                SAFE_FREE(state.request->extra_data.data);
1528
 
 
1529
 
                iov[0].iov_base = (void *)state.response;
1530
 
                iov[0].iov_len = sizeof(struct winbindd_response);
1531
 
                iov_count = 1;
1532
 
 
1533
 
                if (state.response->length > sizeof(struct winbindd_response)) {
1534
 
                        iov[1].iov_base =
1535
 
                                (void *)state.response->extra_data.data;
1536
 
                        iov[1].iov_len = state.response->length-iov[0].iov_len;
1537
 
                        iov_count = 2;
1538
 
                }
1539
 
 
1540
 
                DEBUG(10, ("Writing %d bytes to parent\n",
1541
 
                           (int)state.response->length));
1542
 
 
1543
 
                if (write_data_iov(state.sock, iov, iov_count) !=
1544
 
                    state.response->length) {
1545
 
                        DEBUG(0, ("Could not write result\n"));
1546
 
                        exit(1);
1547
 
                }
1548
 
                TALLOC_FREE(frame);
1549
 
        }
1550
 
}