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, &section);
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, &section);
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, &section);
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, &section);
277         if (retval == PROF_NO_SECTION)
278             retval = profile_add_node(section, *cpp, 0, &section);
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