1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * prof_set.c --- routines that expose the public interfaces for
4 * inserting, updating and deleting items from the profile.
5 *
6 * WARNING: These routines only look at the first file opened in the
7 * profile. It's not clear how to handle multiple files, actually.
8 * In the future it may be necessary to modify this public interface,
9 * or possibly add higher level functions to support this correctly.
10 *
11 * WARNING: We're not yet doing locking yet, either.
12 *
13 */
14
15 #include "prof_int.h"
16
17 #include <stdio.h>
18 #include <string.h>
19 #ifdef HAVE_STDLIB_H
20 #include <stdlib.h>
21 #endif
22 #include <errno.h>
23
rw_setup(profile_t profile)24 static errcode_t rw_setup(profile_t profile)
25 {
26 prf_file_t file;
27 errcode_t retval = 0;
28
29 if (!profile)
30 return PROF_NO_PROFILE;
31
32 if (profile->magic != PROF_MAGIC_PROFILE)
33 return PROF_MAGIC_PROFILE;
34
35 file = profile->first_file;
36
37 profile_lock_global();
38
39 /* Don't update the file if we've already made modifications */
40 if (file->data->flags & PROFILE_FILE_DIRTY) {
41 profile_unlock_global();
42 return 0;
43 }
44
45 if ((file->data->flags & PROFILE_FILE_SHARED) != 0) {
46 prf_data_t new_data;
47 new_data = profile_make_prf_data(file->data->filespec);
48 if (new_data == NULL) {
49 retval = ENOMEM;
50 } else {
51 retval = k5_mutex_init(&new_data->lock);
52 if (retval == 0) {
53 new_data->root = NULL;
54 new_data->flags = file->data->flags & ~PROFILE_FILE_SHARED;
55 new_data->timestamp = 0;
56 new_data->upd_serial = file->data->upd_serial;
57 }
58 }
59
60 if (retval != 0) {
61 profile_unlock_global();
62 free(new_data);
63 return retval;
64 }
65 profile_dereference_data_locked(file->data);
66 file->data = new_data;
67 }
68
69 profile_unlock_global();
70 retval = profile_update_file(file, NULL);
71
72 return retval;
73 }
74
75
76 /*
77 * Delete or update a particular child node
78 *
79 * ADL - 2/23/99, rewritten TYT 2/25/99
80 */
81 errcode_t KRB5_CALLCONV
profile_update_relation(profile_t profile,const char ** names,const char * old_value,const char * new_value)82 profile_update_relation(profile_t profile, const char **names,
83 const char *old_value, const char *new_value)
84 {
85 errcode_t retval;
86 struct profile_node *section, *node;
87 void *state;
88 const char **cpp;
89
90 if (profile->vt) {
91 if (!profile->vt->update_relation)
92 return PROF_UNSUPPORTED;
93 return profile->vt->update_relation(profile->cbdata, names, old_value,
94 new_value);
95 }
96
97 retval = rw_setup(profile);
98 if (retval)
99 return retval;
100
101 if (names == 0 || names[0] == 0 || names[1] == 0)
102 return PROF_BAD_NAMESET;
103
104 if (!old_value || !*old_value)
105 return PROF_EINVAL;
106
107 k5_mutex_lock(&profile->first_file->data->lock);
108 section = profile->first_file->data->root;
109 for (cpp = names; cpp[1]; cpp++) {
110 state = 0;
111 retval = profile_find_node(section, *cpp, 0, 1,
112 &state, §ion);
113 if (retval) {
114 k5_mutex_unlock(&profile->first_file->data->lock);
115 return retval;
116 }
117 }
118
119 state = 0;
120 retval = profile_find_node(section, *cpp, old_value, 0, &state, &node);
121 if (retval == 0) {
122 if (new_value)
123 retval = profile_set_relation_value(node, new_value);
124 else
125 retval = profile_remove_node(node);
126 }
127 if (retval == 0)
128 profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
129 k5_mutex_unlock(&profile->first_file->data->lock);
130
131 return retval;
132 }
133
134 /*
135 * Clear a particular all of the relations with a specific name.
136 *
137 * TYT - 2/25/99
138 */
139 errcode_t KRB5_CALLCONV
profile_clear_relation(profile_t profile,const char ** names)140 profile_clear_relation(profile_t profile, const char **names)
141 {
142 errcode_t retval;
143 struct profile_node *section, *node;
144 void *state;
145 const char **cpp;
146
147 if (profile->vt) {
148 if (!profile->vt->update_relation)
149 return PROF_UNSUPPORTED;
150 return profile->vt->update_relation(profile->cbdata, names, NULL,
151 NULL);
152 }
153
154 retval = rw_setup(profile);
155 if (retval)
156 return retval;
157
158 if (names == 0 || names[0] == 0 || names[1] == 0)
159 return PROF_BAD_NAMESET;
160
161 section = profile->first_file->data->root;
162 for (cpp = names; cpp[1]; cpp++) {
163 state = 0;
164 retval = profile_find_node(section, *cpp, 0, 1,
165 &state, §ion);
166 if (retval)
167 return retval;
168 }
169
170 state = 0;
171 do {
172 retval = profile_find_node(section, *cpp, 0, 0, &state, &node);
173 if (retval)
174 return retval;
175 retval = profile_remove_node(node);
176 if (retval)
177 return retval;
178 } while (state);
179
180 profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
181
182 return 0;
183 }
184
185 /*
186 * Rename a particular section; if the new_section name is NULL,
187 * delete it.
188 *
189 * ADL - 2/23/99, rewritten TYT 2/25/99
190 */
191 errcode_t KRB5_CALLCONV
profile_rename_section(profile_t profile,const char ** names,const char * new_name)192 profile_rename_section(profile_t profile, const char **names,
193 const char *new_name)
194 {
195 errcode_t retval;
196 struct profile_node *section, *node;
197 void *state;
198 const char **cpp;
199
200 if (profile->vt) {
201 if (!profile->vt->rename_section)
202 return PROF_UNSUPPORTED;
203 return profile->vt->rename_section(profile->cbdata, names, new_name);
204 }
205
206 retval = rw_setup(profile);
207 if (retval)
208 return retval;
209
210 if (names == 0 || names[0] == 0)
211 return PROF_BAD_NAMESET;
212
213 k5_mutex_lock(&profile->first_file->data->lock);
214 section = profile->first_file->data->root;
215 for (cpp = names; cpp[1]; cpp++) {
216 state = 0;
217 retval = profile_find_node(section, *cpp, 0, 1,
218 &state, §ion);
219 if (retval) {
220 k5_mutex_unlock(&profile->first_file->data->lock);
221 return retval;
222 }
223 }
224
225 state = 0;
226 retval = profile_find_node(section, *cpp, 0, 1, &state, &node);
227 if (retval == 0) {
228 if (new_name)
229 retval = profile_rename_node(node, new_name);
230 else
231 retval = profile_remove_node(node);
232 }
233 if (retval == 0)
234 profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
235 k5_mutex_unlock(&profile->first_file->data->lock);
236 return retval;
237 }
238
239 /*
240 * Insert a new relation. If the new_value argument is NULL, then
241 * create a new section instead.
242 *
243 * Note: if the intermediate sections do not exist, this function will
244 * automatically create them.
245 *
246 * ADL - 2/23/99, rewritten TYT 2/25/99
247 */
248 errcode_t KRB5_CALLCONV
profile_add_relation(profile_t profile,const char ** names,const char * new_value)249 profile_add_relation(profile_t profile, const char **names,
250 const char *new_value)
251 {
252 errcode_t retval;
253 struct profile_node *section;
254 const char **cpp;
255 void *state;
256
257 if (profile->vt) {
258 if (!profile->vt->add_relation)
259 return PROF_UNSUPPORTED;
260 return profile->vt->add_relation(profile->cbdata, names, new_value);
261 }
262
263 retval = rw_setup(profile);
264 if (retval)
265 return retval;
266
267 /* Require at least two names for a new relation, one for a new section. */
268 if (names == 0 || names[0] == 0 || (names[1] == 0 && new_value))
269 return PROF_BAD_NAMESET;
270
271 k5_mutex_lock(&profile->first_file->data->lock);
272 section = profile->first_file->data->root;
273 for (cpp = names; cpp[1]; cpp++) {
274 state = 0;
275 retval = profile_find_node(section, *cpp, 0, 1,
276 &state, §ion);
277 if (retval == PROF_NO_SECTION)
278 retval = profile_add_node(section, *cpp, 0, §ion);
279 if (retval) {
280 k5_mutex_unlock(&profile->first_file->data->lock);
281 return retval;
282 }
283 }
284
285 if (new_value == 0) {
286 state = 0;
287 retval = profile_find_node(section, *cpp, 0, 1, &state, 0);
288 if (retval == 0) {
289 k5_mutex_unlock(&profile->first_file->data->lock);
290 return PROF_EXISTS;
291 } else if (retval != PROF_NO_SECTION) {
292 k5_mutex_unlock(&profile->first_file->data->lock);
293 return retval;
294 }
295 }
296
297 retval = profile_add_node(section, *cpp, new_value, 0);
298 if (retval) {
299 k5_mutex_unlock(&profile->first_file->data->lock);
300 return retval;
301 }
302
303 profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
304 k5_mutex_unlock(&profile->first_file->data->lock);
305 return 0;
306 }
307