• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/samba-3.5.8/source4/lib/ldb/tools/
1/*
2   ldb database library
3
4   Copyright (C) Andrew Tridgell  2004
5
6     ** NOTE! The following LGPL license applies to the ldb
7     ** library. This does NOT imply that all of Samba is released
8     ** under the LGPL
9
10   This library is free software; you can redistribute it and/or
11   modify it under the terms of the GNU Lesser General Public
12   License as published by the Free Software Foundation; either
13   version 3 of the License, or (at your option) any later version.
14
15   This library 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 GNU
18   Lesser General Public License for more details.
19
20   You should have received a copy of the GNU Lesser General Public
21   License along with this library; if not, see <http://www.gnu.org/licenses/>.
22*/
23
24/*
25 *  Name: ldb
26 *
27 *  Component: ldbedit
28 *
29 *  Description: utility for ldb database editing
30 *
31 *  Author: Andrew Tridgell
32 */
33#include "ldb_includes.h"
34#include "ldb.h"
35#include "tools/cmdline.h"
36
37static struct ldb_cmdline *options;
38
39/*
40  debug routine
41*/
42static void ldif_write_msg(struct ldb_context *ldb,
43			   FILE *f,
44			   enum ldb_changetype changetype,
45			   struct ldb_message *msg)
46{
47	struct ldb_ldif ldif;
48	ldif.changetype = changetype;
49	ldif.msg = msg;
50	ldb_ldif_write_file(ldb, f, &ldif);
51}
52
53/*
54  modify a database record so msg1 becomes msg2
55  returns the number of modified elements
56*/
57static int modify_record(struct ldb_context *ldb,
58			 struct ldb_message *msg1,
59			 struct ldb_message *msg2)
60{
61	struct ldb_message *mod;
62
63	mod = ldb_msg_diff(ldb, msg1, msg2);
64	if (mod == NULL) {
65		fprintf(stderr, "Failed to calculate message differences\n");
66		return -1;
67	}
68
69	if (mod->num_elements == 0) {
70		return 0;
71	}
72
73	if (options->verbose > 0) {
74		ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_MODIFY, mod);
75	}
76
77	if (ldb_modify(ldb, mod) != 0) {
78		fprintf(stderr, "failed to modify %s - %s\n",
79			ldb_dn_get_linearized(msg1->dn), ldb_errstring(ldb));
80		return -1;
81	}
82
83	return mod->num_elements;
84}
85
86/*
87  find dn in msgs[]
88*/
89static struct ldb_message *msg_find(struct ldb_context *ldb,
90				    struct ldb_message **msgs,
91				    int count,
92				    struct ldb_dn *dn)
93{
94	int i;
95	for (i=0;i<count;i++) {
96		if (ldb_dn_compare(dn, msgs[i]->dn) == 0) {
97			return msgs[i];
98		}
99	}
100	return NULL;
101}
102
103/*
104  merge the changes in msgs2 into the messages from msgs1
105*/
106static int merge_edits(struct ldb_context *ldb,
107		       struct ldb_message **msgs1, int count1,
108		       struct ldb_message **msgs2, int count2)
109{
110	int i;
111	struct ldb_message *msg;
112	int ret = 0;
113	int adds=0, modifies=0, deletes=0;
114
115	if (ldb_transaction_start(ldb) != 0) {
116		fprintf(stderr, "Failed to start transaction: %s\n", ldb_errstring(ldb));
117		return -1;
118	}
119
120	/* do the adds and modifies */
121	for (i=0;i<count2;i++) {
122		msg = msg_find(ldb, msgs1, count1, msgs2[i]->dn);
123		if (!msg) {
124			if (options->verbose > 0) {
125				ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_ADD, msgs2[i]);
126			}
127			if (ldb_add(ldb, msgs2[i]) != 0) {
128				fprintf(stderr, "failed to add %s - %s\n",
129					ldb_dn_get_linearized(msgs2[i]->dn),
130					ldb_errstring(ldb));
131				ldb_transaction_cancel(ldb);
132				return -1;
133			}
134			adds++;
135		} else {
136			if (modify_record(ldb, msg, msgs2[i]) > 0) {
137				modifies++;
138			}
139		}
140	}
141
142	/* do the deletes */
143	for (i=0;i<count1;i++) {
144		msg = msg_find(ldb, msgs2, count2, msgs1[i]->dn);
145		if (!msg) {
146			if (options->verbose > 0) {
147				ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_DELETE, msgs1[i]);
148			}
149			if (ldb_delete(ldb, msgs1[i]->dn) != 0) {
150				fprintf(stderr, "failed to delete %s - %s\n",
151					ldb_dn_get_linearized(msgs1[i]->dn),
152					ldb_errstring(ldb));
153				ldb_transaction_cancel(ldb);
154				return -1;
155			}
156			deletes++;
157		}
158	}
159
160	if (ldb_transaction_commit(ldb) != 0) {
161		fprintf(stderr, "Failed to commit transaction: %s\n", ldb_errstring(ldb));
162		return -1;
163	}
164
165	printf("# %d adds  %d modifies  %d deletes\n", adds, modifies, deletes);
166
167	return ret;
168}
169
170/*
171  save a set of messages as ldif to a file
172*/
173static int save_ldif(struct ldb_context *ldb,
174		     FILE *f, struct ldb_message **msgs, int count)
175{
176	int i;
177
178	fprintf(f, "# editing %d records\n", count);
179
180	for (i=0;i<count;i++) {
181		struct ldb_ldif ldif;
182		fprintf(f, "# record %d\n", i+1);
183
184		ldif.changetype = LDB_CHANGETYPE_NONE;
185		ldif.msg = msgs[i];
186
187		ldb_ldif_write_file(ldb, f, &ldif);
188	}
189
190	return 0;
191}
192
193
194/*
195  edit the ldb search results in msgs using the user selected editor
196*/
197static int do_edit(struct ldb_context *ldb, struct ldb_message **msgs1, int count1,
198		   const char *editor)
199{
200	int fd, ret;
201	FILE *f;
202	char file_template[] = "/tmp/ldbedit.XXXXXX";
203	char *cmd;
204	struct ldb_ldif *ldif;
205	struct ldb_message **msgs2 = NULL;
206	int count2 = 0;
207
208	/* write out the original set of messages to a temporary
209	   file */
210	fd = mkstemp(file_template);
211
212	if (fd == -1) {
213		perror(file_template);
214		return -1;
215	}
216
217	f = fdopen(fd, "r+");
218
219	if (!f) {
220		perror("fopen");
221		close(fd);
222		unlink(file_template);
223		return -1;
224	}
225
226	if (save_ldif(ldb, f, msgs1, count1) != 0) {
227		return -1;
228	}
229
230	fclose(f);
231
232	cmd = talloc_asprintf(ldb, "%s %s", editor, file_template);
233
234	if (!cmd) {
235		unlink(file_template);
236		fprintf(stderr, "out of memory\n");
237		return -1;
238	}
239
240	/* run the editor */
241	ret = system(cmd);
242	talloc_free(cmd);
243
244	if (ret != 0) {
245		unlink(file_template);
246		fprintf(stderr, "edit with %s failed\n", editor);
247		return -1;
248	}
249
250	/* read the resulting ldif into msgs2 */
251	f = fopen(file_template, "r");
252	if (!f) {
253		perror(file_template);
254		return -1;
255	}
256
257	while ((ldif = ldb_ldif_read_file(ldb, f))) {
258		msgs2 = talloc_realloc(ldb, msgs2, struct ldb_message *, count2+1);
259		if (!msgs2) {
260			fprintf(stderr, "out of memory");
261			return -1;
262		}
263		msgs2[count2++] = ldif->msg;
264	}
265
266	fclose(f);
267	unlink(file_template);
268
269	return merge_edits(ldb, msgs1, count1, msgs2, count2);
270}
271
272static void usage(void)
273{
274	printf("Usage: ldbedit <options> <expression> <attributes ...>\n");
275	ldb_cmdline_help("ldbedit", stdout);
276	exit(1);
277}
278
279int main(int argc, const char **argv)
280{
281	struct ldb_context *ldb;
282	struct ldb_result *result = NULL;
283	struct ldb_dn *basedn = NULL;
284	int ret;
285	const char *expression = "(|(objectClass=*)(distinguishedName=*))";
286	const char * const * attrs = NULL;
287
288	ldb = ldb_init(NULL, NULL);
289
290	options = ldb_cmdline_process(ldb, argc, argv, usage);
291
292	/* the check for '=' is for compatibility with ldapsearch */
293	if (options->argc > 0 &&
294	    strchr(options->argv[0], '=')) {
295		expression = options->argv[0];
296		options->argv++;
297		options->argc--;
298	}
299
300	if (options->argc > 0) {
301		attrs = (const char * const *)(options->argv);
302	}
303
304	if (options->basedn != NULL) {
305		basedn = ldb_dn_new(ldb, ldb, options->basedn);
306		if ( ! ldb_dn_validate(basedn)) {
307			printf("Invalid Base DN format\n");
308			exit(1);
309		}
310	}
311
312	ret = ldb_search(ldb, ldb, &result, basedn, options->scope, attrs, "%s", expression);
313	if (ret != LDB_SUCCESS) {
314		printf("search failed - %s\n", ldb_errstring(ldb));
315		exit(1);
316	}
317
318	if (result->count == 0) {
319		printf("no matching records - cannot edit\n");
320		return 0;
321	}
322
323	do_edit(ldb, result->msgs, result->count, options->editor);
324
325	if (result) {
326		ret = talloc_free(result);
327		if (ret == -1) {
328			fprintf(stderr, "talloc_free failed\n");
329			exit(1);
330		}
331	}
332
333	talloc_free(ldb);
334	return 0;
335}
336