xref: /freebsd/crypto/krb5/src/util/profile/prof_set.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
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, &section);
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, &section);
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, &section);
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, &section);
272         if (retval == PROF_NO_SECTION)
273             retval = profile_add_node(section, *cpp, NULL, 0, &section);
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