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