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: ldbmodify
28  *
29  *  Description: utility to modify records - modelled on ldapmodify
30  *
31  *  Author: Andrew Tridgell
32  */
33 
34 #include "replace.h"
35 #include "ldb.h"
36 #include "tools/cmdline.h"
37 #include "ldbutil.h"
38 #include "include/ldb_private.h"
39 
40 static struct ldb_cmdline *options;
41 
usage(struct ldb_context * ldb)42 static void usage(struct ldb_context *ldb)
43 {
44 	printf("Usage: ldbmodify <options> <ldif...>\n");
45 	printf("Modifies a ldb based upon ldif change records\n\n");
46 	ldb_cmdline_help(ldb, "ldbmodify", stdout);
47 	exit(LDB_ERR_OPERATIONS_ERROR);
48 }
49 
50 /*
51   process modifies for one file
52 */
process_file(struct ldb_context * ldb,FILE * f,unsigned int * count)53 static int process_file(struct ldb_context *ldb, FILE *f, unsigned int *count)
54 {
55 	struct ldb_ldif *ldif;
56 	int fun_ret = LDB_SUCCESS, ret;
57 	struct ldb_control **req_ctrls = ldb_parse_control_strings(ldb, ldb, (const char **)options->controls);
58 	struct ldif_read_file_state state = {
59 		.f = f
60 	};
61 
62 	if (options->controls != NULL &&  req_ctrls== NULL) {
63 		printf("parsing controls failed: %s\n", ldb_errstring(ldb));
64 		exit(LDB_ERR_OPERATIONS_ERROR);
65 	}
66 
67 	fun_ret = ldb_transaction_start(ldb);
68 	if (fun_ret != LDB_SUCCESS) {
69 		fprintf(stderr, "ERR: (%s) on transaction start\n",
70 			ldb_errstring(ldb));
71 		return fun_ret;
72 	}
73 
74 	while ((ldif = ldb_ldif_read_file_state(ldb, &state))) {
75 		struct ldb_dn *olddn;
76 		bool deleteoldrdn = false;
77 		struct ldb_dn *newdn;
78 		const char *errstr = NULL;
79 
80 		switch (ldif->changetype) {
81 		case LDB_CHANGETYPE_NONE:
82 		case LDB_CHANGETYPE_ADD:
83 			ret = ldb_add_ctrl(ldb, ldif->msg,req_ctrls);
84 			break;
85 		case LDB_CHANGETYPE_DELETE:
86 			ret = ldb_delete_ctrl(ldb, ldif->msg->dn,req_ctrls);
87 			break;
88 		case LDB_CHANGETYPE_MODIFY:
89 			ret = ldb_modify_ctrl(ldb, ldif->msg,req_ctrls);
90 			break;
91 		case LDB_CHANGETYPE_MODRDN:
92 			ret = ldb_ldif_parse_modrdn(ldb, ldif, ldif, &olddn,
93 						    NULL, &deleteoldrdn,
94 						    NULL, &newdn);
95 			if (ret == LDB_SUCCESS) {
96 				if (deleteoldrdn) {
97 					ret = ldb_rename(ldb, olddn, newdn);
98 				} else {
99 					errstr = "modrdn: deleteoldrdn=0 "
100 						 "not supported.";
101 					ret = LDB_ERR_CONSTRAINT_VIOLATION;
102 				}
103 			}
104 			break;
105 		}
106 		if (ret != LDB_SUCCESS) {
107 			if (errstr == NULL) {
108 				errstr = ldb_errstring(ldb);
109 			}
110 			fprintf(stderr, "ERR: (%s) \"%s\" on DN %s at block before line %llu\n",
111 				ldb_strerror(ret),
112 				errstr, ldb_dn_get_linearized(ldif->msg->dn),
113 				(unsigned long long)state.line_no);
114 			fun_ret = ret;
115 		} else {
116 			(*count)++;
117 			if (options->verbose) {
118 				printf("Modified %s\n", ldb_dn_get_linearized(ldif->msg->dn));
119 			}
120 		}
121 		ldb_ldif_read_free(ldb, ldif);
122 		if (ret) {
123 			break;
124 		}
125 	}
126 
127 	if (fun_ret == LDB_SUCCESS && !feof(f)) {
128 		fprintf(stderr, "Failed to parse ldif\n");
129 		fun_ret = LDB_ERR_OPERATIONS_ERROR;
130 	}
131 
132 	if (fun_ret == LDB_SUCCESS) {
133 		fun_ret = ldb_transaction_commit(ldb);
134 		if (fun_ret != LDB_SUCCESS) {
135 			fprintf(stderr, "ERR: (%s) on transaction commit\n",
136 				ldb_errstring(ldb));
137 		}
138 	} else {
139 		ldb_transaction_cancel(ldb);
140 	}
141 
142 	return fun_ret;
143 }
144 
main(int argc,const char ** argv)145 int main(int argc, const char **argv)
146 {
147 	struct ldb_context *ldb;
148 	unsigned int i, count = 0;
149 	int ret = LDB_SUCCESS;
150 	TALLOC_CTX *mem_ctx = talloc_new(NULL);
151 
152 	ldb = ldb_init(mem_ctx, NULL);
153 	if (ldb == NULL) {
154 		return LDB_ERR_OPERATIONS_ERROR;
155 	}
156 
157 	options = ldb_cmdline_process(ldb, argc, argv, usage);
158 
159 	if (options->argc == 0) {
160 		ret = process_file(ldb, stdin, &count);
161 	} else {
162 		for (i=0;i<options->argc;i++) {
163 			const char *fname = options->argv[i];
164 			FILE *f;
165 			f = fopen(fname, "r");
166 			if (!f) {
167 				perror(fname);
168 				return LDB_ERR_OPERATIONS_ERROR;
169 			}
170 			ret = process_file(ldb, f, &count);
171 			fclose(f);
172 		}
173 	}
174 
175 	talloc_free(mem_ctx);
176 
177 	if (ret) {
178 		printf("Modify failed after processing %u records\n", count);
179 	} else {
180 		printf("Modified %u records successfully\n", count);
181 	}
182 
183 	return ret;
184 }
185