dssync keytab: add prefix parameter to add_to_keytab_entries() for flexibility.
[kamenim/samba.git] / source3 / libnet / libnet_dssync_keytab.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Guenther Deschner <gd@samba.org> 2008
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "libnet/libnet.h"
22
23 #if defined(HAVE_ADS) && defined(ENCTYPE_ARCFOUR_HMAC)
24
25 static NTSTATUS add_to_keytab_entries(TALLOC_CTX *mem_ctx,
26                                       struct libnet_keytab_context *ctx,
27                                       uint32_t kvno,
28                                       const char *name,
29                                       const char *prefix,
30                                       DATA_BLOB blob)
31 {
32         struct libnet_keytab_entry entry;
33
34         entry.kvno = kvno;
35         entry.name = talloc_strdup(mem_ctx, name);
36         entry.principal = talloc_asprintf(mem_ctx, "%s%s%s@%s",
37                                           prefix ? prefix : "",
38                                           prefix ? "/" : "",
39                                           name, ctx->dns_domain_name);
40         entry.password = blob;
41         NT_STATUS_HAVE_NO_MEMORY(entry.name);
42         NT_STATUS_HAVE_NO_MEMORY(entry.principal);
43         NT_STATUS_HAVE_NO_MEMORY(entry.password.data);
44
45         ADD_TO_ARRAY(mem_ctx, struct libnet_keytab_entry, entry,
46                      &ctx->entries, &ctx->count);
47         NT_STATUS_HAVE_NO_MEMORY(ctx->entries);
48
49         return NT_STATUS_OK;
50 }
51
52 static NTSTATUS keytab_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx)
53 {
54         krb5_error_code ret = 0;
55         struct libnet_keytab_context *keytab_ctx;
56
57         ret = libnet_keytab_init(mem_ctx, ctx->output_filename, &keytab_ctx);
58         if (ret) {
59                 return krb5_to_nt_status(ret);
60         }
61
62         keytab_ctx->dns_domain_name = ctx->dns_domain_name;
63         ctx->private_data = keytab_ctx;
64
65         return NT_STATUS_OK;
66 }
67
68 static NTSTATUS keytab_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx)
69 {
70         NTSTATUS status = NT_STATUS_OK;
71         krb5_error_code ret = 0;
72         struct libnet_keytab_context *keytab_ctx =
73                 (struct libnet_keytab_context *)ctx->private_data;
74
75         ret = libnet_keytab_add(keytab_ctx);
76         if (ret) {
77                 status = krb5_to_nt_status(ret);
78                 ctx->error_message = talloc_asprintf(mem_ctx,
79                         "Failed to add entries to keytab %s: %s",
80                         keytab_ctx->keytab_name, error_message(ret));
81                 goto done;
82         }
83
84         ctx->result_message = talloc_asprintf(mem_ctx,
85                 "Vampired %d accounts to keytab %s",
86                 keytab_ctx->count,
87                 keytab_ctx->keytab_name);
88
89 done:
90         TALLOC_FREE(keytab_ctx);
91         return status;
92 }
93
94 /****************************************************************
95 ****************************************************************/
96
97 static NTSTATUS parse_object(TALLOC_CTX *mem_ctx,
98                              struct libnet_keytab_context *ctx,
99                              struct drsuapi_DsReplicaObjectListItemEx *cur)
100 {
101         NTSTATUS status = NT_STATUS_OK;
102         uchar nt_passwd[16];
103         struct libnet_keytab_entry entry;
104         DATA_BLOB *blob;
105         int i = 0;
106         struct drsuapi_DsReplicaAttribute *attr;
107         bool got_pwd = false;
108
109         char *upn = NULL;
110         char *name = NULL;
111         uint32_t kvno = 0;
112         uint32_t uacc = 0;
113         uint32_t sam_type = 0;
114
115         uint32_t pwd_history_len = 0;
116         uint8_t *pwd_history = NULL;
117
118         ZERO_STRUCT(nt_passwd);
119
120         for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
121
122                 attr = &cur->object.attribute_ctr.attributes[i];
123
124                 if (attr->value_ctr.num_values != 1) {
125                         continue;
126                 }
127
128                 if (!attr->value_ctr.values[0].blob) {
129                         continue;
130                 }
131
132                 blob = attr->value_ctr.values[0].blob;
133
134                 switch (attr->attid) {
135                         case DRSUAPI_ATTRIBUTE_unicodePwd:
136
137                                 if (blob->length != 16) {
138                                         break;
139                                 }
140
141                                 memcpy(&nt_passwd, blob->data, 16);
142                                 got_pwd = true;
143
144                                 /* pick the kvno from the meta_data version,
145                                  * thanks, metze, for explaining this */
146
147                                 if (!cur->meta_data_ctr) {
148                                         break;
149                                 }
150                                 if (cur->meta_data_ctr->count !=
151                                     cur->object.attribute_ctr.num_attributes) {
152                                         break;
153                                 }
154                                 kvno = cur->meta_data_ctr->meta_data[i].version;
155                                 break;
156                         case DRSUAPI_ATTRIBUTE_ntPwdHistory:
157                                 pwd_history_len = blob->length / 16;
158                                 pwd_history = blob->data;
159                                 break;
160                         case DRSUAPI_ATTRIBUTE_msDS_KeyVersionNumber:
161                                 kvno = IVAL(blob->data, 0);
162                                 break;
163                         case DRSUAPI_ATTRIBUTE_userPrincipalName:
164                                 pull_string_talloc(mem_ctx, NULL, 0, &upn,
165                                                    blob->data, blob->length,
166                                                    STR_UNICODE);
167                                 break;
168                         case DRSUAPI_ATTRIBUTE_sAMAccountName:
169                                 pull_string_talloc(mem_ctx, NULL, 0, &name,
170                                                    blob->data, blob->length,
171                                                    STR_UNICODE);
172                                 break;
173                         case DRSUAPI_ATTRIBUTE_sAMAccountType:
174                                 sam_type = IVAL(blob->data, 0);
175                                 break;
176                         case DRSUAPI_ATTRIBUTE_userAccountControl:
177                                 uacc = IVAL(blob->data, 0);
178                                 break;
179                         default:
180                                 break;
181                 }
182         }
183
184         if (!got_pwd || !name) {
185                 return NT_STATUS_OK;
186         }
187
188         DEBUG(1,("#%02d: %s:%d, ", ctx->count, name, kvno));
189         DEBUGADD(1,("sAMAccountType: 0x%08x, userAccountControl: 0x%08x ",
190                 sam_type, uacc));
191         if (upn) {
192                 DEBUGADD(1,("upn: %s", upn));
193         }
194         DEBUGADD(1,("\n"));
195
196         status = add_to_keytab_entries(mem_ctx, ctx, kvno, name, NULL,
197                                        data_blob_talloc(mem_ctx, nt_passwd, 16));
198
199         if (!NT_STATUS_IS_OK(status)) {
200                 return status;
201         }
202
203         if ((kvno < 0) && (kvno < pwd_history_len)) {
204                 return status;
205         }
206
207         /* add password history */
208
209         /* skip first entry */
210         if (got_pwd) {
211                 kvno--;
212                 i = 1;
213         } else {
214                 i = 0;
215         }
216
217         for (; i<pwd_history_len; i++) {
218
219                 entry.kvno = kvno--;
220                 entry.name = talloc_strdup(mem_ctx, name);
221                 entry.principal = talloc_asprintf(mem_ctx, "%s@%s",
222                                                   name, ctx->dns_domain_name);
223                 entry.password = data_blob_talloc(mem_ctx, &pwd_history[i*16], 16);
224                 NT_STATUS_HAVE_NO_MEMORY(entry.name);
225                 NT_STATUS_HAVE_NO_MEMORY(entry.principal);
226                 NT_STATUS_HAVE_NO_MEMORY(entry.password.data);
227
228                 ADD_TO_ARRAY(mem_ctx, struct libnet_keytab_entry, entry,
229                              &ctx->entries, &ctx->count);
230         }
231
232         return status;
233 }
234
235 /****************************************************************
236 ****************************************************************/
237
238 static NTSTATUS keytab_process_objects(struct dssync_context *ctx,
239                                        TALLOC_CTX *mem_ctx,
240                                        struct drsuapi_DsReplicaObjectListItemEx *cur,
241                                        struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
242 {
243         NTSTATUS status = NT_STATUS_OK;
244         struct libnet_keytab_context *keytab_ctx =
245                 (struct libnet_keytab_context *)ctx->private_data;
246
247         for (; cur; cur = cur->next_object) {
248                 status = parse_object(mem_ctx, keytab_ctx, cur);
249                 if (!NT_STATUS_IS_OK(status)) {
250                         goto out;
251                 }
252         }
253
254  out:
255         return status;
256 }
257
258 #else
259
260 static NTSTATUS keytab_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx)
261 {
262         return NT_STATUS_NOT_SUPPORTED;
263 }
264
265 static NTSTATUS keytab_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx)
266 {
267         return NT_STATUS_NOT_SUPPORTED;
268 }
269
270 static NTSTATUS keytab_process_objects(struct dssync_context *ctx,
271                                        TALLOC_CTX *mem_ctx,
272                                        struct drsuapi_DsReplicaObjectListItemEx *cur,
273                                        struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
274 {
275         return NT_STATUS_NOT_SUPPORTED;
276 }
277 #endif /* defined(HAVE_ADS) && defined(ENCTYPE_ARCFOUR_HMAC) */
278
279 const struct dssync_ops libnet_dssync_keytab_ops = {
280         .startup                = keytab_startup,
281         .process_objects        = keytab_process_objects,
282         .finish                 = keytab_finish,
283 };