~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/libnet/libnet_samsync_ldb.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS implementation.
 
3
   
 
4
   Extract the user/system database from a remote SamSync server
 
5
 
 
6
   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
 
7
   Copyright (C) Andrew Tridgell 2004
 
8
   Copyright (C) Volker Lendecke 2004
 
9
   
 
10
   This program is free software; you can redistribute it and/or modify
 
11
   it under the terms of the GNU General Public License as published by
 
12
   the Free Software Foundation; either version 3 of the License, or
 
13
   (at your option) any later version.
 
14
   
 
15
   This program is distributed in the hope that it will be useful,
 
16
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
   GNU General Public License for more details.
 
19
   
 
20
   You should have received a copy of the GNU General Public License
 
21
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
22
*/
 
23
 
 
24
 
 
25
#include "includes.h"
 
26
#include "libnet/libnet.h"
 
27
#include "libcli/ldap/ldap_ndr.h"
 
28
#include "dsdb/samdb/samdb.h"
 
29
#include "auth/auth.h"
 
30
#include "../lib/util/util_ldb.h"
 
31
#include "librpc/gen_ndr/ndr_misc.h"
 
32
#include "ldb_wrap.h"
 
33
#include "libcli/security/security.h"
 
34
#include "librpc/rpc/dcerpc.h"
 
35
#include "param/param.h"
 
36
 
 
37
struct samsync_ldb_secret {
 
38
        struct samsync_ldb_secret *prev, *next;
 
39
        DATA_BLOB secret;
 
40
        char *name;
 
41
        NTTIME mtime;
 
42
};
 
43
 
 
44
struct samsync_ldb_trusted_domain {
 
45
        struct samsync_ldb_trusted_domain *prev, *next;
 
46
        struct dom_sid *sid;
 
47
        char *name;
 
48
};
 
49
 
 
50
struct samsync_ldb_state {
 
51
        /* Values from the LSA lookup */
 
52
        const struct libnet_SamSync_state *samsync_state;
 
53
 
 
54
        struct dom_sid *dom_sid[3];
 
55
        struct ldb_context *sam_ldb, *remote_ldb;
 
56
        struct ldb_dn *base_dn[3];
 
57
        struct samsync_ldb_secret *secrets;
 
58
        struct samsync_ldb_trusted_domain *trusted_domains;
 
59
};
 
60
 
 
61
static NTSTATUS samsync_ldb_add_foreignSecurityPrincipal(TALLOC_CTX *mem_ctx,
 
62
                                                         struct samsync_ldb_state *state,
 
63
                                                         struct dom_sid *sid,
 
64
                                                         struct ldb_dn **fsp_dn,
 
65
                                                         char **error_string)
 
66
{
 
67
        const char *sidstr = dom_sid_string(mem_ctx, sid);
 
68
        /* We assume that ForeignSecurityPrincipals are under the BASEDN of the main domain */
 
69
        struct ldb_dn *basedn = samdb_search_dn(state->sam_ldb, mem_ctx,
 
70
                                                state->base_dn[SAM_DATABASE_DOMAIN],
 
71
                                                "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
 
72
        struct ldb_message *msg;
 
73
        int ret;
 
74
 
 
75
        if (!sidstr) {
 
76
                return NT_STATUS_NO_MEMORY;
 
77
        }
 
78
 
 
79
        if (basedn == NULL) {
 
80
                *error_string = talloc_asprintf(mem_ctx, 
 
81
                                                "Failed to find DN for "
 
82
                                                "ForeignSecurityPrincipal container under %s",
 
83
                                                ldb_dn_get_linearized(state->base_dn[SAM_DATABASE_DOMAIN]));
 
84
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
85
        }
 
86
        
 
87
        msg = ldb_msg_new(mem_ctx);
 
88
        if (msg == NULL) {
 
89
                return NT_STATUS_NO_MEMORY;
 
90
        }
 
91
 
 
92
        /* add core elements to the ldb_message for the alias */
 
93
        msg->dn = basedn;
 
94
        if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
 
95
                return NT_STATUS_UNSUCCESSFUL;
 
96
        
 
97
        samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
 
98
                             "objectClass",
 
99
                             "foreignSecurityPrincipal");
 
100
 
 
101
        *fsp_dn = msg->dn;
 
102
 
 
103
        /* create the alias */
 
104
        ret = ldb_add(state->sam_ldb, msg);
 
105
        if (ret != 0) {
 
106
                *error_string = talloc_asprintf(mem_ctx, "Failed to create foreignSecurityPrincipal "
 
107
                                                "record %s: %s",
 
108
                                                ldb_dn_get_linearized(msg->dn),
 
109
                                                ldb_errstring(state->sam_ldb));
 
110
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
111
        }
 
112
        return NT_STATUS_OK;
 
113
}
 
114
 
 
115
static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx,
 
116
                                          struct samsync_ldb_state *state,
 
117
                                          enum netr_SamDatabaseID database,
 
118
                                          struct netr_DELTA_ENUM *delta,
 
119
                                          char **error_string) 
 
120
{
 
121
        struct netr_DELTA_DOMAIN *domain = delta->delta_union.domain;
 
122
        const char *domain_name = domain->domain_name.string;
 
123
        struct ldb_message *msg;
 
124
        int ret;
 
125
        
 
126
        msg = ldb_msg_new(mem_ctx);
 
127
        if (msg == NULL) {
 
128
                return NT_STATUS_NO_MEMORY;
 
129
        }
 
130
 
 
131
        if (database == SAM_DATABASE_DOMAIN) {
 
132
                struct ldb_dn *partitions_basedn;
 
133
                const char *domain_attrs[] =  {"nETBIOSName", "nCName", NULL};
 
134
                struct ldb_message **msgs_domain;
 
135
                int ret_domain;
 
136
 
 
137
                partitions_basedn = samdb_partitions_dn(state->sam_ldb, mem_ctx);
 
138
 
 
139
                ret_domain = gendb_search(state->sam_ldb, mem_ctx, partitions_basedn, &msgs_domain, domain_attrs,
 
140
                                          "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", 
 
141
                                          domain_name);
 
142
                if (ret_domain == -1) {
 
143
                        *error_string = talloc_asprintf(mem_ctx, "gendb_search for domain failed: %s", ldb_errstring(state->sam_ldb));
 
144
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
145
                }
 
146
                
 
147
                if (ret_domain != 1) {
 
148
                        *error_string = talloc_asprintf(mem_ctx, "Failed to find existing domain record for %s: %d results", domain_name,
 
149
                                                        ret_domain);
 
150
                        return NT_STATUS_NO_SUCH_DOMAIN;                
 
151
                }
 
152
 
 
153
                state->base_dn[database] = samdb_result_dn(state->sam_ldb, state, msgs_domain[0], "nCName", NULL);
 
154
 
 
155
                if (state->dom_sid[database]) {
 
156
                        /* Update the domain sid with the incoming
 
157
                         * domain (found on LSA pipe, database sid may
 
158
                         * be random) */
 
159
                        samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, 
 
160
                                              msg, "objectSid", state->dom_sid[database]);
 
161
                } else {
 
162
                        /* Well, we will have to use the one from the database */
 
163
                        state->dom_sid[database] = samdb_search_dom_sid(state->sam_ldb, state,
 
164
                                                                        state->base_dn[database], 
 
165
                                                                        "objectSid", NULL);
 
166
                }
 
167
 
 
168
                if (state->samsync_state->domain_guid) {
 
169
                        enum ndr_err_code ndr_err;
 
170
                        struct ldb_val v;
 
171
                        ndr_err = ndr_push_struct_blob(&v, msg, NULL, 
 
172
                                                       state->samsync_state->domain_guid,
 
173
                                                         (ndr_push_flags_fn_t)ndr_push_GUID);
 
174
                        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
175
                                *error_string = talloc_asprintf(mem_ctx, "ndr_push of domain GUID failed!");
 
176
                                return ndr_map_error2ntstatus(ndr_err);
 
177
                        }
 
178
                        
 
179
                        ldb_msg_add_value(msg, "objectGUID", &v, NULL);
 
180
                }
 
181
        } else if (database == SAM_DATABASE_BUILTIN) {
 
182
                /* work out the builtin_dn - useful for so many calls its worth
 
183
                   fetching here */
 
184
                const char *dnstring = samdb_search_string(state->sam_ldb, mem_ctx, NULL,
 
185
                                                           "distinguishedName", "objectClass=builtinDomain");
 
186
                state->base_dn[database] = ldb_dn_new(state, state->sam_ldb, dnstring);
 
187
                if ( ! ldb_dn_validate(state->base_dn[database])) {
 
188
                        return NT_STATUS_INTERNAL_ERROR;
 
189
                }
 
190
        } else {
 
191
                /* PRIVs DB */
 
192
                return NT_STATUS_INVALID_PARAMETER;
 
193
        }
 
194
 
 
195
        msg->dn = talloc_reference(mem_ctx, state->base_dn[database]);
 
196
        if (!msg->dn) {
 
197
                return NT_STATUS_NO_MEMORY;
 
198
        }
 
199
 
 
200
        samdb_msg_add_string(state->sam_ldb, mem_ctx, 
 
201
                             msg, "oEMInformation", domain->oem_information.string);
 
202
 
 
203
        samdb_msg_add_int64(state->sam_ldb, mem_ctx, 
 
204
                            msg, "forceLogoff", domain->force_logoff_time);
 
205
 
 
206
        samdb_msg_add_uint(state->sam_ldb, mem_ctx, 
 
207
                           msg, "minPwdLen", domain->min_password_length);
 
208
 
 
209
        samdb_msg_add_int64(state->sam_ldb, mem_ctx, 
 
210
                            msg, "maxPwdAge", domain->max_password_age);
 
211
 
 
212
        samdb_msg_add_int64(state->sam_ldb, mem_ctx, 
 
213
                            msg, "minPwdAge", domain->min_password_age);
 
214
 
 
215
        samdb_msg_add_uint(state->sam_ldb, mem_ctx, 
 
216
                           msg, "pwdHistoryLength", domain->password_history_length);
 
217
 
 
218
        samdb_msg_add_uint64(state->sam_ldb, mem_ctx, 
 
219
                             msg, "modifiedCount", 
 
220
                             domain->sequence_num);
 
221
 
 
222
        samdb_msg_add_uint64(state->sam_ldb, mem_ctx, 
 
223
                             msg, "creationTime", domain->domain_create_time);
 
224
 
 
225
        /* TODO: Account lockout, password properties */
 
226
        
 
227
        ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
 
228
 
 
229
        if (ret) {
 
230
                return NT_STATUS_INTERNAL_ERROR;
 
231
        }
 
232
        return NT_STATUS_OK;
 
233
}
 
234
 
 
235
static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
 
236
                                        struct samsync_ldb_state *state,
 
237
                                        enum netr_SamDatabaseID database,
 
238
                                        struct netr_DELTA_ENUM *delta,
 
239
                                        char **error_string) 
 
240
{
 
241
        uint32_t rid = delta->delta_id_union.rid;
 
242
        struct netr_DELTA_USER *user = delta->delta_union.user;
 
243
        const char *container, *obj_class;
 
244
        char *cn_name;
 
245
        int cn_name_len;
 
246
        const struct dom_sid *user_sid;
 
247
        struct ldb_message *msg;
 
248
        struct ldb_message **msgs;
 
249
        struct ldb_message **remote_msgs = NULL;
 
250
        int ret, i;
 
251
        uint32_t acb;
 
252
        bool add = false;
 
253
        const char *attrs[] = { NULL };
 
254
        /* we may change this to a global search, then fill in only the things not in ldap later */
 
255
        const char *remote_attrs[] = { "userPrincipalName", "servicePrincipalName", 
 
256
                                       "msDS-KeyVersionNumber", "objectGUID", NULL};
 
257
 
 
258
        user_sid = dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid);
 
259
        if (!user_sid) {
 
260
                return NT_STATUS_NO_MEMORY;
 
261
        }
 
262
 
 
263
        msg = ldb_msg_new(mem_ctx);
 
264
        if (msg == NULL) {
 
265
                return NT_STATUS_NO_MEMORY;
 
266
        }
 
267
 
 
268
        msg->dn = NULL;
 
269
        /* search for the user, by rid */
 
270
        ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
 
271
                           &msgs, attrs, "(&(objectClass=user)(objectSid=%s))", 
 
272
                           ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
 
273
 
 
274
        if (ret == -1) {
 
275
                *error_string = talloc_asprintf(mem_ctx, "LDB for user %s failed: %s", 
 
276
                                                dom_sid_string(mem_ctx, user_sid),
 
277
                                                ldb_errstring(state->sam_ldb));
 
278
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
279
        } else if (ret == 0) {
 
280
                add = true;
 
281
        } else if (ret > 1) {
 
282
                *error_string = talloc_asprintf(mem_ctx, "More than one user with SID: %s in local LDB", 
 
283
                                                dom_sid_string(mem_ctx, user_sid));
 
284
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
285
        } else {
 
286
                msg->dn = msgs[0]->dn;
 
287
                talloc_steal(msg, msgs[0]->dn);
 
288
        }
 
289
 
 
290
        /* and do the same on the remote database */
 
291
        if (state->remote_ldb) {
 
292
                ret = gendb_search(state->remote_ldb, mem_ctx, state->base_dn[database],
 
293
                                   &remote_msgs, remote_attrs, "(&(objectClass=user)(objectSid=%s))", 
 
294
                                   ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
 
295
                
 
296
                if (ret == -1) {
 
297
                        *error_string = talloc_asprintf(mem_ctx, "remote LDAP for user %s failed: %s", 
 
298
                                                        dom_sid_string(mem_ctx, user_sid),
 
299
                                                        ldb_errstring(state->remote_ldb));
 
300
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
301
                } else if (ret == 0) {
 
302
                        *error_string = talloc_asprintf(mem_ctx, "User exists in samsync but not in remote LDAP domain! (base: %s, SID: %s)", 
 
303
                                                        ldb_dn_get_linearized(state->base_dn[database]),
 
304
                                                        dom_sid_string(mem_ctx, user_sid));
 
305
                        return NT_STATUS_NO_SUCH_USER;
 
306
                } else if (ret > 1) {
 
307
                        *error_string = talloc_asprintf(mem_ctx, "More than one user in remote LDAP domain with SID: %s", 
 
308
                                                        dom_sid_string(mem_ctx, user_sid));
 
309
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
310
                        
 
311
                        /* Try to put things in the same location as the remote server */
 
312
                } else if (add) {
 
313
                        msg->dn = remote_msgs[0]->dn;
 
314
                        talloc_steal(msg, remote_msgs[0]->dn);
 
315
                }
 
316
        }
 
317
 
 
318
        cn_name   = talloc_strdup(mem_ctx, user->account_name.string);
 
319
        NT_STATUS_HAVE_NO_MEMORY(cn_name);
 
320
        cn_name_len = strlen(cn_name);
 
321
 
 
322
#define ADD_OR_DEL(type, attrib, field) do {                            \
 
323
                if (user->field) {                                      \
 
324
                        samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
 
325
                                               attrib, user->field);    \
 
326
                } else if (!add) {                                      \
 
327
                        samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
 
328
                                             attrib);                   \
 
329
                }                                                       \
 
330
        } while (0);
 
331
 
 
332
        ADD_OR_DEL(string, "samAccountName", account_name.string);
 
333
        ADD_OR_DEL(string, "displayName", full_name.string);
 
334
 
 
335
        if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg, 
 
336
                                  "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
 
337
                return NT_STATUS_NO_MEMORY; 
 
338
        }
 
339
 
 
340
        ADD_OR_DEL(uint, "primaryGroupID", primary_gid);
 
341
        ADD_OR_DEL(string, "homeDirectory", home_directory.string);
 
342
        ADD_OR_DEL(string, "homeDrive", home_drive.string);
 
343
        ADD_OR_DEL(string, "scriptPath", logon_script.string);
 
344
        ADD_OR_DEL(string, "description", description.string);
 
345
        ADD_OR_DEL(string, "userWorkstations", workstations.string);
 
346
 
 
347
        ADD_OR_DEL(uint64, "lastLogon", last_logon);
 
348
        ADD_OR_DEL(uint64, "lastLogoff", last_logoff);
 
349
 
 
350
        if (samdb_msg_add_logon_hours(state->sam_ldb, mem_ctx, msg, "logonHours", &user->logon_hours) != 0) { 
 
351
                return NT_STATUS_NO_MEMORY; 
 
352
        }
 
353
 
 
354
        ADD_OR_DEL(uint, "badPwdCount", bad_password_count);
 
355
        ADD_OR_DEL(uint, "logonCount", logon_count);
 
356
 
 
357
        ADD_OR_DEL(uint64, "pwdLastSet", last_password_change);
 
358
        ADD_OR_DEL(uint64, "accountExpires", acct_expiry);
 
359
        
 
360
        if (samdb_msg_add_acct_flags(state->sam_ldb, mem_ctx, msg, 
 
361
                                     "userAccountControl", user->acct_flags) != 0) { 
 
362
                return NT_STATUS_NO_MEMORY; 
 
363
        } 
 
364
        
 
365
        if (!add) {
 
366
                /* Passwords.  Ensure there is no plaintext stored against
 
367
                 * this entry, as we only have hashes */
 
368
                samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
 
369
                                     "userPassword"); 
 
370
        }
 
371
        if (user->lm_password_present) {
 
372
                samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,  
 
373
                                   "dBCSPwd", &user->lmpassword);
 
374
        } else if (!add) {
 
375
                samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
 
376
                                     "dBCSPwd"); 
 
377
        }
 
378
        if (user->nt_password_present) {
 
379
                samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,  
 
380
                                   "unicodePwd", &user->ntpassword);
 
381
        } else if (!add) {
 
382
                samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
 
383
                                     "unicodePwd"); 
 
384
        }
 
385
            
 
386
        ADD_OR_DEL(string, "comment", comment.string);
 
387
 
 
388
        if (samdb_msg_add_parameters(state->sam_ldb, mem_ctx, msg, "userParameters", &user->parameters) != 0) {
 
389
                return NT_STATUS_NO_MEMORY;
 
390
        }
 
391
 
 
392
        ADD_OR_DEL(uint, "countryCode", country_code);
 
393
        ADD_OR_DEL(uint, "codePage", code_page);
 
394
 
 
395
        ADD_OR_DEL(string, "profilePath", profile_path.string);
 
396
 
 
397
#undef ADD_OR_DEL
 
398
 
 
399
        for (i=0; remote_attrs[i]; i++) {
 
400
                struct ldb_message_element *el = ldb_msg_find_element(remote_msgs[0], remote_attrs[i]);
 
401
                if (!el) {
 
402
                        samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
 
403
                                             remote_attrs[i]); 
 
404
                } else {
 
405
                        ldb_msg_add(msg, el, LDB_FLAG_MOD_REPLACE);
 
406
                }
 
407
        }
 
408
 
 
409
        acb = user->acct_flags;
 
410
        if (acb & (ACB_WSTRUST)) {
 
411
                cn_name[cn_name_len - 1] = '\0';
 
412
                container = "Computers";
 
413
                obj_class = "computer";
 
414
                
 
415
        } else if (acb & ACB_SVRTRUST) {
 
416
                if (cn_name[cn_name_len - 1] != '$') {
 
417
                        return NT_STATUS_FOOBAR;                
 
418
                }
 
419
                cn_name[cn_name_len - 1] = '\0';
 
420
                container = "Domain Controllers";
 
421
                obj_class = "computer";
 
422
        } else {
 
423
                container = "Users";
 
424
                obj_class = "user";
 
425
        }
 
426
        if (add) {
 
427
                samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, 
 
428
                                     "objectClass", obj_class);
 
429
                if (!msg->dn) {
 
430
                        msg->dn = ldb_dn_copy(mem_ctx, state->base_dn[database]);
 
431
                        ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=%s", cn_name, container);
 
432
                        if (!msg->dn) {
 
433
                                return NT_STATUS_NO_MEMORY;             
 
434
                        }
 
435
                }
 
436
 
 
437
                ret = ldb_add(state->sam_ldb, msg);
 
438
                if (ret != 0) {
 
439
                        struct ldb_dn *first_try_dn = msg->dn;
 
440
                        /* Try again with the default DN */
 
441
                        if (!remote_msgs) {
 
442
                                *error_string = talloc_asprintf(mem_ctx, "Failed to create user record.  Tried %s: %s",
 
443
                                                                ldb_dn_get_linearized(first_try_dn),
 
444
                                                                ldb_errstring(state->sam_ldb));
 
445
                                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
446
                        } else {
 
447
                                msg->dn = talloc_steal(msg, remote_msgs[0]->dn);
 
448
                                ret = ldb_add(state->sam_ldb, msg);
 
449
                                if (ret != 0) {
 
450
                                        *error_string = talloc_asprintf(mem_ctx, "Failed to create user record.  Tried both %s and %s: %s",
 
451
                                                                        ldb_dn_get_linearized(first_try_dn),
 
452
                                                                        ldb_dn_get_linearized(msg->dn),
 
453
                                                                        ldb_errstring(state->sam_ldb));
 
454
                                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
455
                                }
 
456
                        }
 
457
                }
 
458
        } else {
 
459
                ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
 
460
                if (ret != 0) {
 
461
                        *error_string = talloc_asprintf(mem_ctx, "Failed to modify user record %s: %s",
 
462
                                                        ldb_dn_get_linearized(msg->dn),
 
463
                                                        ldb_errstring(state->sam_ldb));
 
464
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
465
                }
 
466
        }
 
467
 
 
468
        return NT_STATUS_OK;
 
469
}
 
470
 
 
471
static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx,
 
472
                                        struct samsync_ldb_state *state,
 
473
                                        enum netr_SamDatabaseID database,
 
474
                                        struct netr_DELTA_ENUM *delta,
 
475
                                        char **error_string) 
 
476
{
 
477
        uint32_t rid = delta->delta_id_union.rid;
 
478
        struct ldb_message **msgs;
 
479
        int ret;
 
480
        const char *attrs[] = { NULL };
 
481
 
 
482
        /* search for the user, by rid */
 
483
        ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
 
484
                           &msgs, attrs, "(&(objectClass=user)(objectSid=%s))", 
 
485
                           ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
 
486
 
 
487
        if (ret == -1) {
 
488
                *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
 
489
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
490
        } else if (ret == 0) {
 
491
                return NT_STATUS_NO_SUCH_USER;
 
492
        } else if (ret > 1) {
 
493
                *error_string = talloc_asprintf(mem_ctx, "More than one user with SID: %s", 
 
494
                                                dom_sid_string(mem_ctx, 
 
495
                                                               dom_sid_add_rid(mem_ctx, 
 
496
                                                                               state->dom_sid[database], 
 
497
                                                                               rid)));
 
498
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
499
        }
 
500
 
 
501
        ret = ldb_delete(state->sam_ldb, msgs[0]->dn);
 
502
        if (ret != 0) {
 
503
                *error_string = talloc_asprintf(mem_ctx, "Failed to delete user record %s: %s",
 
504
                                                ldb_dn_get_linearized(msgs[0]->dn),
 
505
                                                ldb_errstring(state->sam_ldb));
 
506
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
507
        }
 
508
 
 
509
        return NT_STATUS_OK;
 
510
}
 
511
 
 
512
static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
 
513
                                         struct samsync_ldb_state *state,
 
514
                                         enum netr_SamDatabaseID database,
 
515
                                         struct netr_DELTA_ENUM *delta,
 
516
                                         char **error_string) 
 
517
{
 
518
        uint32_t rid = delta->delta_id_union.rid;
 
519
        struct netr_DELTA_GROUP *group = delta->delta_union.group;
 
520
        const char *container, *obj_class;
 
521
        const char *cn_name;
 
522
 
 
523
        struct ldb_message *msg;
 
524
        struct ldb_message **msgs;
 
525
        int ret;
 
526
        bool add = false;
 
527
        const char *attrs[] = { NULL };
 
528
 
 
529
        msg = ldb_msg_new(mem_ctx);
 
530
        if (msg == NULL) {
 
531
                return NT_STATUS_NO_MEMORY;
 
532
        }
 
533
 
 
534
        /* search for the group, by rid */
 
535
        ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
 
536
                           "(&(objectClass=group)(objectSid=%s))", 
 
537
                           ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
 
538
 
 
539
        if (ret == -1) {
 
540
                *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
 
541
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
542
        } else if (ret == 0) {
 
543
                add = true;
 
544
        } else if (ret > 1) {
 
545
                *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s", 
 
546
                                                dom_sid_string(mem_ctx, 
 
547
                                                               dom_sid_add_rid(mem_ctx, 
 
548
                                                                               state->dom_sid[database], 
 
549
                                                                               rid)));
 
550
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
551
        } else {
 
552
                msg->dn = talloc_steal(msg, msgs[0]->dn);
 
553
        }
 
554
 
 
555
        cn_name   = group->group_name.string;
 
556
 
 
557
#define ADD_OR_DEL(type, attrib, field) do {                            \
 
558
                if (group->field) {                                     \
 
559
                        samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
 
560
                                               attrib, group->field);   \
 
561
                } else if (!add) {                                      \
 
562
                        samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
 
563
                                             attrib);                   \
 
564
                }                                                       \
 
565
        } while (0);
 
566
 
 
567
        ADD_OR_DEL(string, "samAccountName", group_name.string);
 
568
 
 
569
        if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg, 
 
570
                                  "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
 
571
                return NT_STATUS_NO_MEMORY; 
 
572
        }
 
573
 
 
574
        ADD_OR_DEL(string, "description", description.string);
 
575
 
 
576
#undef ADD_OR_DEL
 
577
 
 
578
        container = "Users";
 
579
        obj_class = "group";
 
580
 
 
581
        if (add) {
 
582
                samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, 
 
583
                                     "objectClass", obj_class);
 
584
                msg->dn = ldb_dn_copy(mem_ctx, state->base_dn[database]);
 
585
                ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=%s", cn_name, container);
 
586
                if (!msg->dn) {
 
587
                        return NT_STATUS_NO_MEMORY;             
 
588
                }
 
589
 
 
590
                ret = ldb_add(state->sam_ldb, msg);
 
591
                if (ret != 0) {
 
592
                        *error_string = talloc_asprintf(mem_ctx, "Failed to create group record %s: %s",
 
593
                                                        ldb_dn_get_linearized(msg->dn),
 
594
                                                        ldb_errstring(state->sam_ldb));
 
595
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
596
                }
 
597
        } else {
 
598
                ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
 
599
                if (ret != 0) {
 
600
                        *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
 
601
                                                        ldb_dn_get_linearized(msg->dn),
 
602
                                                        ldb_errstring(state->sam_ldb));
 
603
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
604
                }
 
605
        }
 
606
 
 
607
        return NT_STATUS_OK;
 
608
}
 
609
 
 
610
static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx,
 
611
                                         struct samsync_ldb_state *state,
 
612
                                         enum netr_SamDatabaseID database,
 
613
                                         struct netr_DELTA_ENUM *delta,
 
614
                                         char **error_string) 
 
615
{
 
616
        uint32_t rid = delta->delta_id_union.rid;
 
617
        struct ldb_message **msgs;
 
618
        int ret;
 
619
        const char *attrs[] = { NULL };
 
620
 
 
621
        /* search for the group, by rid */
 
622
        ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
 
623
                           "(&(objectClass=group)(objectSid=%s))", 
 
624
                           ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
 
625
 
 
626
        if (ret == -1) {
 
627
                *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
 
628
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
629
        } else if (ret == 0) {
 
630
                return NT_STATUS_NO_SUCH_GROUP;
 
631
        } else if (ret > 1) {
 
632
                *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s", 
 
633
                                                dom_sid_string(mem_ctx, 
 
634
                                                               dom_sid_add_rid(mem_ctx, 
 
635
                                                                               state->dom_sid[database], 
 
636
                                                                               rid)));
 
637
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
638
        }
 
639
        
 
640
        ret = ldb_delete(state->sam_ldb, msgs[0]->dn);
 
641
        if (ret != 0) {
 
642
                *error_string = talloc_asprintf(mem_ctx, "Failed to delete group record %s: %s",
 
643
                                                ldb_dn_get_linearized(msgs[0]->dn),
 
644
                                                ldb_errstring(state->sam_ldb));
 
645
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
646
        }
 
647
 
 
648
        return NT_STATUS_OK;
 
649
}
 
650
 
 
651
static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
 
652
                                                struct samsync_ldb_state *state,
 
653
                                                enum netr_SamDatabaseID database,
 
654
                                                struct netr_DELTA_ENUM *delta,
 
655
                                                char **error_string) 
 
656
{
 
657
        uint32_t rid = delta->delta_id_union.rid;
 
658
        struct netr_DELTA_GROUP_MEMBER *group_member = delta->delta_union.group_member;
 
659
        struct ldb_message *msg;
 
660
        struct ldb_message **msgs;
 
661
        int ret;
 
662
        const char *attrs[] = { NULL };
 
663
        int i;
 
664
 
 
665
        msg = ldb_msg_new(mem_ctx);
 
666
        if (msg == NULL) {
 
667
                return NT_STATUS_NO_MEMORY;
 
668
        }
 
669
 
 
670
        /* search for the group, by rid */
 
671
        ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
 
672
                           "(&(objectClass=group)(objectSid=%s))", 
 
673
                           ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
 
674
 
 
675
        if (ret == -1) {
 
676
                *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
 
677
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
678
        } else if (ret == 0) {
 
679
                return NT_STATUS_NO_SUCH_GROUP;
 
680
        } else if (ret > 1) {
 
681
                *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s", 
 
682
                                                dom_sid_string(mem_ctx, 
 
683
                                                               dom_sid_add_rid(mem_ctx, 
 
684
                                                                               state->dom_sid[database], 
 
685
                                                                               rid)));
 
686
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
687
        } else {
 
688
                msg->dn = talloc_steal(msg, msgs[0]->dn);
 
689
        }
 
690
        
 
691
        talloc_free(msgs);
 
692
 
 
693
        for (i=0; i<group_member->num_rids; i++) {
 
694
                /* search for the group, by rid */
 
695
                ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
 
696
                                   "(&(objectClass=user)(objectSid=%s))", 
 
697
                                   ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], group_member->rids[i]))); 
 
698
                
 
699
                if (ret == -1) {
 
700
                        *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
 
701
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
702
                } else if (ret == 0) {
 
703
                        return NT_STATUS_NO_SUCH_USER;
 
704
                } else if (ret > 1) {
 
705
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
706
                } else {
 
707
                        samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", ldb_dn_alloc_linearized(mem_ctx, msgs[0]->dn));
 
708
                }
 
709
                
 
710
                talloc_free(msgs);
 
711
        }
 
712
        
 
713
        ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
 
714
        if (ret != 0) {
 
715
                *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
 
716
                                                ldb_dn_get_linearized(msg->dn),
 
717
                                                ldb_errstring(state->sam_ldb));
 
718
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
719
        }
 
720
 
 
721
        return NT_STATUS_OK;
 
722
}
 
723
 
 
724
static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
 
725
                                         struct samsync_ldb_state *state,
 
726
                                         enum netr_SamDatabaseID database,
 
727
                                         struct netr_DELTA_ENUM *delta,
 
728
                                         char **error_string) 
 
729
{
 
730
        uint32_t rid = delta->delta_id_union.rid;
 
731
        struct netr_DELTA_ALIAS *alias = delta->delta_union.alias;
 
732
        const char *container, *obj_class;
 
733
        const char *cn_name;
 
734
 
 
735
        struct ldb_message *msg;
 
736
        struct ldb_message **msgs;
 
737
        int ret;
 
738
        bool add = false;
 
739
        const char *attrs[] = { NULL };
 
740
 
 
741
        msg = ldb_msg_new(mem_ctx);
 
742
        if (msg == NULL) {
 
743
                return NT_STATUS_NO_MEMORY;
 
744
        }
 
745
 
 
746
        /* search for the alias, by rid */
 
747
        ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
 
748
                           "(&(objectClass=group)(objectSid=%s))", 
 
749
                           ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
 
750
 
 
751
        if (ret == -1) {
 
752
                *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
 
753
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
754
        } else if (ret == 0) {
 
755
                add = true;
 
756
        } else if (ret > 1) {
 
757
                *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s", 
 
758
                                                dom_sid_string(mem_ctx, 
 
759
                                                               dom_sid_add_rid(mem_ctx, 
 
760
                                                                               state->dom_sid[database], 
 
761
                                                                               rid)));
 
762
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
763
        } else {
 
764
                msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
 
765
        }
 
766
 
 
767
        cn_name   = alias->alias_name.string;
 
768
 
 
769
#define ADD_OR_DEL(type, attrib, field) do {                            \
 
770
                if (alias->field) {                                     \
 
771
                        samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
 
772
                                               attrib, alias->field);   \
 
773
                } else if (!add) {                                      \
 
774
                        samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
 
775
                                             attrib);                   \
 
776
                }                                                       \
 
777
        } while (0);
 
778
 
 
779
        ADD_OR_DEL(string, "samAccountName", alias_name.string);
 
780
 
 
781
        if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg, 
 
782
                                  "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
 
783
                return NT_STATUS_NO_MEMORY; 
 
784
        }
 
785
 
 
786
        ADD_OR_DEL(string, "description", description.string);
 
787
 
 
788
#undef ADD_OR_DEL
 
789
 
 
790
        samdb_msg_add_uint(state->sam_ldb, mem_ctx, msg, "groupType", 0x80000004);
 
791
 
 
792
        container = "Users";
 
793
        obj_class = "group";
 
794
 
 
795
        if (add) {
 
796
                samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, 
 
797
                                     "objectClass", obj_class);
 
798
                msg->dn = ldb_dn_copy(mem_ctx, state->base_dn[database]);
 
799
                ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=%s", cn_name, container);
 
800
                if (!msg->dn) {
 
801
                        return NT_STATUS_NO_MEMORY;             
 
802
                }
 
803
 
 
804
                ret = ldb_add(state->sam_ldb, msg);
 
805
                if (ret != 0) {
 
806
                        *error_string = talloc_asprintf(mem_ctx, "Failed to create alias record %s: %s",
 
807
                                                        ldb_dn_get_linearized(msg->dn),
 
808
                                                        ldb_errstring(state->sam_ldb));
 
809
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
810
                }
 
811
        } else {
 
812
                ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
 
813
                if (ret != 0) {
 
814
                        *error_string = talloc_asprintf(mem_ctx, "Failed to modify alias record %s: %s",
 
815
                                                        ldb_dn_get_linearized(msg->dn),
 
816
                                                        ldb_errstring(state->sam_ldb));
 
817
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
818
                }
 
819
        }
 
820
 
 
821
        return NT_STATUS_OK;
 
822
}
 
823
 
 
824
static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
 
825
                                         struct samsync_ldb_state *state,
 
826
                                         enum netr_SamDatabaseID database,
 
827
                                         struct netr_DELTA_ENUM *delta,
 
828
                                         char **error_string) 
 
829
{
 
830
        uint32_t rid = delta->delta_id_union.rid;
 
831
        struct ldb_message **msgs;
 
832
        int ret;
 
833
        const char *attrs[] = { NULL };
 
834
 
 
835
        /* search for the alias, by rid */
 
836
        ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
 
837
                           "(&(objectClass=group)(objectSid=%s))", 
 
838
                           ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
 
839
 
 
840
        if (ret == -1) {
 
841
                *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
 
842
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
843
        } else if (ret == 0) {
 
844
                return NT_STATUS_NO_SUCH_ALIAS;
 
845
        } else if (ret > 1) {
 
846
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
847
        }
 
848
 
 
849
        ret = ldb_delete(state->sam_ldb, msgs[0]->dn);
 
850
        if (ret != 0) {
 
851
                *error_string = talloc_asprintf(mem_ctx, "Failed to delete alias record %s: %s",
 
852
                                                ldb_dn_get_linearized(msgs[0]->dn),
 
853
                                                ldb_errstring(state->sam_ldb));
 
854
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
855
        }
 
856
 
 
857
        return NT_STATUS_OK;
 
858
}
 
859
 
 
860
static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
 
861
                                                struct samsync_ldb_state *state,
 
862
                                                enum netr_SamDatabaseID database,
 
863
                                                struct netr_DELTA_ENUM *delta,
 
864
                                                char **error_string) 
 
865
{
 
866
        uint32_t rid = delta->delta_id_union.rid;
 
867
        struct netr_DELTA_ALIAS_MEMBER *alias_member = delta->delta_union.alias_member;
 
868
        struct ldb_message *msg;
 
869
        struct ldb_message **msgs;
 
870
        int ret;
 
871
        const char *attrs[] = { NULL };
 
872
        int i;
 
873
 
 
874
        msg = ldb_msg_new(mem_ctx);
 
875
        if (msg == NULL) {
 
876
                return NT_STATUS_NO_MEMORY;
 
877
        }
 
878
 
 
879
        /* search for the alias, by rid */
 
880
        ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
 
881
                           "(&(objectClass=group)(objectSid=%s))", 
 
882
                           ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
 
883
                
 
884
        if (ret == -1) {
 
885
                *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
 
886
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
887
        } else if (ret == 0) {
 
888
                return NT_STATUS_NO_SUCH_GROUP;
 
889
        } else if (ret > 1) {
 
890
                *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s", 
 
891
                                                dom_sid_string(mem_ctx, 
 
892
                                                               dom_sid_add_rid(mem_ctx, 
 
893
                                                                               state->dom_sid[database], 
 
894
                                                                               rid)));
 
895
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
896
        } else {
 
897
                msg->dn = talloc_steal(msg, msgs[0]->dn);
 
898
        }
 
899
        
 
900
        talloc_free(msgs);
 
901
 
 
902
        for (i=0; i<alias_member->sids.num_sids; i++) {
 
903
                struct ldb_dn *alias_member_dn;
 
904
                /* search for members, in the top basedn (normal users are builtin aliases) */
 
905
                ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
 
906
                                   "(objectSid=%s)", 
 
907
                                   ldap_encode_ndr_dom_sid(mem_ctx, alias_member->sids.sids[i].sid)); 
 
908
 
 
909
                if (ret == -1) {
 
910
                        *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
 
911
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
912
                } else if (ret == 0) {
 
913
                        NTSTATUS nt_status;
 
914
                        nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
 
915
                                                                             alias_member->sids.sids[i].sid, 
 
916
                                                                             &alias_member_dn, 
 
917
                                                                             error_string);
 
918
                        if (!NT_STATUS_IS_OK(nt_status)) {
 
919
                                return nt_status;
 
920
                        }
 
921
                } else if (ret > 1) {
 
922
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
923
                } else {
 
924
                        alias_member_dn = msgs[0]->dn;
 
925
                }
 
926
                samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", ldb_dn_alloc_linearized(mem_ctx, alias_member_dn));
 
927
        
 
928
                talloc_free(msgs);
 
929
        }
 
930
 
 
931
        ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
 
932
        if (ret != 0) {
 
933
                *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
 
934
                                                ldb_dn_get_linearized(msg->dn),
 
935
                                                ldb_errstring(state->sam_ldb));
 
936
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
937
        }
 
938
 
 
939
        return NT_STATUS_OK;
 
940
}
 
941
 
 
942
static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx,
 
943
                                           struct samsync_ldb_state *state,
 
944
                                           enum netr_SamDatabaseID database,
 
945
                                           struct netr_DELTA_ENUM *delta,
 
946
                                           char **error_string) 
 
947
{
 
948
        struct dom_sid *sid = delta->delta_id_union.sid;
 
949
        struct netr_DELTA_ACCOUNT *account = delta->delta_union.account;
 
950
 
 
951
        struct ldb_message *msg;
 
952
        struct ldb_message **msgs;
 
953
        struct ldb_dn *privilege_dn;
 
954
        int ret;
 
955
        const char *attrs[] = { NULL };
 
956
        int i;
 
957
 
 
958
        msg = ldb_msg_new(mem_ctx);
 
959
        if (msg == NULL) {
 
960
                return NT_STATUS_NO_MEMORY;
 
961
        }
 
962
 
 
963
        /* search for the account, by sid, in the top basedn */
 
964
        ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
 
965
                           "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, sid)); 
 
966
 
 
967
        if (ret == -1) {
 
968
                *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
 
969
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
970
        } else if (ret == 0) {
 
971
                NTSTATUS nt_status;
 
972
                nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
 
973
                                                                     sid,
 
974
                                                                     &privilege_dn,
 
975
                                                                     error_string);
 
976
                privilege_dn = talloc_steal(msg, privilege_dn);
 
977
                if (!NT_STATUS_IS_OK(nt_status)) {
 
978
                        return nt_status;
 
979
                }
 
980
        } else if (ret > 1) {
 
981
                *error_string = talloc_asprintf(mem_ctx, "More than one account with SID: %s", 
 
982
                                                dom_sid_string(mem_ctx, sid));
 
983
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
984
        } else {
 
985
                privilege_dn = talloc_steal(msg, msgs[0]->dn);
 
986
        }
 
987
 
 
988
        msg->dn = privilege_dn;
 
989
 
 
990
        for (i=0; i< account->privilege_entries; i++) {
 
991
                samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "privilege",
 
992
                                     account->privilege_name[i].string);
 
993
        }
 
994
 
 
995
        ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
 
996
        if (ret != 0) {
 
997
                *error_string = talloc_asprintf(mem_ctx, "Failed to modify privilege record %s",
 
998
                                                ldb_dn_get_linearized(msg->dn));
 
999
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
1000
        }
 
1001
 
 
1002
        return NT_STATUS_OK;
 
1003
}
 
1004
 
 
1005
static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx,
 
1006
                                           struct samsync_ldb_state *state,
 
1007
                                           enum netr_SamDatabaseID database,
 
1008
                                           struct netr_DELTA_ENUM *delta,
 
1009
                                           char **error_string) 
 
1010
{
 
1011
        struct dom_sid *sid = delta->delta_id_union.sid;
 
1012
 
 
1013
        struct ldb_message *msg;
 
1014
        struct ldb_message **msgs;
 
1015
        int ret;
 
1016
        const char *attrs[] = { NULL };
 
1017
 
 
1018
        msg = ldb_msg_new(mem_ctx);
 
1019
        if (msg == NULL) {
 
1020
                return NT_STATUS_NO_MEMORY;
 
1021
        }
 
1022
 
 
1023
        /* search for the account, by sid, in the top basedn */
 
1024
        ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
 
1025
                           "(objectSid=%s)", 
 
1026
                           ldap_encode_ndr_dom_sid(mem_ctx, sid)); 
 
1027
 
 
1028
        if (ret == -1) {
 
1029
                *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
 
1030
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
1031
        } else if (ret == 0) {
 
1032
                return NT_STATUS_NO_SUCH_USER;
 
1033
        } else if (ret > 1) {
 
1034
                *error_string = talloc_asprintf(mem_ctx, "More than one account with SID: %s", 
 
1035
                                                dom_sid_string(mem_ctx, sid));
 
1036
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
1037
        } else {
 
1038
                msg->dn = talloc_steal(msg, msgs[0]->dn);
 
1039
        }
 
1040
 
 
1041
        samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
 
1042
                             "privilage"); 
 
1043
 
 
1044
        ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
 
1045
        if (ret != 0) {
 
1046
                *error_string = talloc_asprintf(mem_ctx, "Failed to modify privilege record %s",
 
1047
                                                ldb_dn_get_linearized(msg->dn));
 
1048
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
 
1049
        }
 
1050
 
 
1051
        return NT_STATUS_OK;
 
1052
}
 
1053
 
 
1054
static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx,              
 
1055
                                      void *private_data,
 
1056
                                      enum netr_SamDatabaseID database,
 
1057
                                      struct netr_DELTA_ENUM *delta,
 
1058
                                      char **error_string)
 
1059
{
 
1060
        NTSTATUS nt_status = NT_STATUS_OK;
 
1061
        struct samsync_ldb_state *state = talloc_get_type(private_data, struct samsync_ldb_state);
 
1062
 
 
1063
        *error_string = NULL;
 
1064
        switch (delta->delta_type) {
 
1065
        case NETR_DELTA_DOMAIN:
 
1066
        {
 
1067
                nt_status = samsync_ldb_handle_domain(mem_ctx, 
 
1068
                                                      state,
 
1069
                                                      database,
 
1070
                                                      delta,
 
1071
                                                      error_string);
 
1072
                break;
 
1073
        }
 
1074
        case NETR_DELTA_USER:
 
1075
        {
 
1076
                nt_status = samsync_ldb_handle_user(mem_ctx, 
 
1077
                                                    state,
 
1078
                                                    database,
 
1079
                                                    delta,
 
1080
                                                    error_string);
 
1081
                break;
 
1082
        }
 
1083
        case NETR_DELTA_DELETE_USER:
 
1084
        {
 
1085
                nt_status = samsync_ldb_delete_user(mem_ctx, 
 
1086
                                                    state,
 
1087
                                                    database,
 
1088
                                                    delta,
 
1089
                                                    error_string);
 
1090
                break;
 
1091
        }
 
1092
        case NETR_DELTA_GROUP:
 
1093
        {
 
1094
                nt_status = samsync_ldb_handle_group(mem_ctx, 
 
1095
                                                     state,
 
1096
                                                     database,
 
1097
                                                     delta,
 
1098
                                                     error_string);
 
1099
                break;
 
1100
        }
 
1101
        case NETR_DELTA_DELETE_GROUP:
 
1102
        {
 
1103
                nt_status = samsync_ldb_delete_group(mem_ctx, 
 
1104
                                                     state,
 
1105
                                                     database,
 
1106
                                                     delta,
 
1107
                                                     error_string);
 
1108
                break;
 
1109
        }
 
1110
        case NETR_DELTA_GROUP_MEMBER:
 
1111
        {
 
1112
                nt_status = samsync_ldb_handle_group_member(mem_ctx, 
 
1113
                                                            state,
 
1114
                                                            database,
 
1115
                                                            delta,
 
1116
                                                            error_string);
 
1117
                break;
 
1118
        }
 
1119
        case NETR_DELTA_ALIAS:
 
1120
        {
 
1121
                nt_status = samsync_ldb_handle_alias(mem_ctx, 
 
1122
                                                     state,
 
1123
                                                     database,
 
1124
                                                     delta,
 
1125
                                                     error_string);
 
1126
                break;
 
1127
        }
 
1128
        case NETR_DELTA_DELETE_ALIAS:
 
1129
        {
 
1130
                nt_status = samsync_ldb_delete_alias(mem_ctx, 
 
1131
                                                     state,
 
1132
                                                     database,
 
1133
                                                     delta,
 
1134
                                                     error_string);
 
1135
                break;
 
1136
        }
 
1137
        case NETR_DELTA_ALIAS_MEMBER:
 
1138
        {
 
1139
                nt_status = samsync_ldb_handle_alias_member(mem_ctx, 
 
1140
                                                            state,
 
1141
                                                            database,
 
1142
                                                            delta,
 
1143
                                                            error_string);
 
1144
                break;
 
1145
        }
 
1146
        case NETR_DELTA_ACCOUNT:
 
1147
        {
 
1148
                nt_status = samsync_ldb_handle_account(mem_ctx, 
 
1149
                                                       state,
 
1150
                                                       database,
 
1151
                                                       delta,
 
1152
                                                       error_string);
 
1153
                break;
 
1154
        }
 
1155
        case NETR_DELTA_DELETE_ACCOUNT:
 
1156
        {
 
1157
                nt_status = samsync_ldb_delete_account(mem_ctx, 
 
1158
                                                       state,
 
1159
                                                       database,
 
1160
                                                       delta,
 
1161
                                                       error_string);
 
1162
                break;
 
1163
        }
 
1164
        default:
 
1165
                /* Can't dump them all right now */
 
1166
                break;
 
1167
        }
 
1168
        if (!NT_STATUS_IS_OK(nt_status) && !*error_string) {
 
1169
                *error_string = talloc_asprintf(mem_ctx, "Failed to handle samsync delta: %s", nt_errstr(nt_status));
 
1170
        }
 
1171
        return nt_status;
 
1172
}
 
1173
 
 
1174
static NTSTATUS libnet_samsync_ldb_init(TALLOC_CTX *mem_ctx,            
 
1175
                                        void *private_data,
 
1176
                                        struct libnet_SamSync_state *samsync_state,
 
1177
                                        char **error_string)
 
1178
{
 
1179
        struct samsync_ldb_state *state = talloc_get_type(private_data, struct samsync_ldb_state);
 
1180
        const char *server = dcerpc_server_name(samsync_state->netlogon_pipe);
 
1181
        char *ldap_url;
 
1182
 
 
1183
        state->samsync_state = samsync_state;
 
1184
 
 
1185
        ZERO_STRUCT(state->dom_sid);
 
1186
        if (state->samsync_state->domain_sid) {
 
1187
                state->dom_sid[SAM_DATABASE_DOMAIN] = dom_sid_dup(state, state->samsync_state->domain_sid);
 
1188
        }
 
1189
 
 
1190
        state->dom_sid[SAM_DATABASE_BUILTIN] = dom_sid_parse_talloc(state, SID_BUILTIN);
 
1191
 
 
1192
        if (state->samsync_state->realm) {
 
1193
                if (!server || !*server) {
 
1194
                        /* huh?  how do we not have a server name?  */
 
1195
                        *error_string = talloc_strdup(mem_ctx, "No DCE/RPC server name available.  How did we connect?");
 
1196
                        return NT_STATUS_INVALID_PARAMETER;
 
1197
                }
 
1198
                ldap_url = talloc_asprintf(state, "ldap://%s", server);
 
1199
                
 
1200
                state->remote_ldb = ldb_wrap_connect(mem_ctx, 
 
1201
                                                     state->samsync_state->machine_net_ctx->event_ctx,
 
1202
                                                     state->samsync_state->machine_net_ctx->lp_ctx, 
 
1203
                                                     ldap_url, 
 
1204
                                                     NULL, state->samsync_state->machine_net_ctx->cred,
 
1205
                                                     0, NULL);
 
1206
                if (!state->remote_ldb) {
 
1207
                        *error_string = talloc_asprintf(mem_ctx, "Failed to connect to remote LDAP server at %s (used to extract additional data in SamSync replication)", ldap_url);
 
1208
                        return NT_STATUS_NO_LOGON_SERVERS;
 
1209
                }
 
1210
        } else {
 
1211
                state->remote_ldb = NULL;
 
1212
        }
 
1213
        return NT_STATUS_OK;
 
1214
}
 
1215
 
 
1216
NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
 
1217
{
 
1218
        NTSTATUS nt_status;
 
1219
        struct libnet_SamSync r2;
 
1220
        struct samsync_ldb_state *state = talloc(mem_ctx, struct samsync_ldb_state);
 
1221
 
 
1222
        if (!state) {
 
1223
                return NT_STATUS_NO_MEMORY;
 
1224
        }
 
1225
 
 
1226
        state->secrets         = NULL;
 
1227
        state->trusted_domains = NULL;
 
1228
 
 
1229
        state->sam_ldb         = samdb_connect(mem_ctx, 
 
1230
                                               ctx->event_ctx,
 
1231
                                               ctx->lp_ctx, 
 
1232
                                               r->in.session_info);
 
1233
 
 
1234
        r2.out.error_string    = NULL;
 
1235
        r2.in.binding_string   = r->in.binding_string;
 
1236
        r2.in.rid_crypt        = true;
 
1237
        r2.in.init_fn          = libnet_samsync_ldb_init;
 
1238
        r2.in.delta_fn         = libnet_samsync_ldb_fn;
 
1239
        r2.in.fn_ctx           = state;
 
1240
        r2.in.machine_account  = NULL; /* TODO:  Create a machine account, fill this in, and the delete it */
 
1241
        nt_status              = libnet_SamSync_netlogon(ctx, state, &r2);
 
1242
        r->out.error_string    = r2.out.error_string;
 
1243
        talloc_steal(mem_ctx, r->out.error_string);
 
1244
 
 
1245
        if (!NT_STATUS_IS_OK(nt_status)) {
 
1246
                talloc_free(state);
 
1247
                return nt_status;
 
1248
        }
 
1249
        talloc_free(state);
 
1250
        return nt_status;
 
1251
}