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