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