17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * prof_set.c --- routines that expose the public interfaces for
37c478bd9Sstevel@tonic-gate  * 	inserting, updating and deleting items from the profile.
47c478bd9Sstevel@tonic-gate  *
57c478bd9Sstevel@tonic-gate  * WARNING: These routines only look at the first file opened in the
67c478bd9Sstevel@tonic-gate  * profile.  It's not clear how to handle multiple files, actually.
77c478bd9Sstevel@tonic-gate  * In the future it may be necessary to modify this public interface,
87c478bd9Sstevel@tonic-gate  * or possibly add higher level functions to support this correctly.
97c478bd9Sstevel@tonic-gate  *
10*1da57d55SToomas Soome  * WARNING: We're not yet doing locking yet, either.
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  */
137c478bd9Sstevel@tonic-gate 
14505d05c7Sgtb #include "prof_int.h"
15505d05c7Sgtb 
167c478bd9Sstevel@tonic-gate #include <stdio.h>
177c478bd9Sstevel@tonic-gate #include <string.h>
187c478bd9Sstevel@tonic-gate #ifdef HAVE_STDLIB_H
197c478bd9Sstevel@tonic-gate #include <stdlib.h>
207c478bd9Sstevel@tonic-gate #endif
217c478bd9Sstevel@tonic-gate #include <errno.h>
227c478bd9Sstevel@tonic-gate 
rw_setup(profile_t profile)23505d05c7Sgtb static errcode_t rw_setup(profile_t profile)
247c478bd9Sstevel@tonic-gate {
257c478bd9Sstevel@tonic-gate    	prf_file_t	file;
26505d05c7Sgtb 	errcode_t	retval = 0;
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate 	if (!profile)
297c478bd9Sstevel@tonic-gate 		return PROF_NO_PROFILE;
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate 	if (profile->magic != PROF_MAGIC_PROFILE)
327c478bd9Sstevel@tonic-gate 		return PROF_MAGIC_PROFILE;
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate 	file = profile->first_file;
35505d05c7Sgtb 
36505d05c7Sgtb 	retval = profile_lock_global();
37505d05c7Sgtb 	if (retval)
38505d05c7Sgtb 	    return retval;
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate 	/* Don't update the file if we've already made modifications */
41505d05c7Sgtb 	if (file->data->flags & PROFILE_FILE_DIRTY) {
42505d05c7Sgtb 	    profile_unlock_global();
43505d05c7Sgtb 	    return 0;
44505d05c7Sgtb 	}
45505d05c7Sgtb 
46505d05c7Sgtb 	if ((file->data->flags & PROFILE_FILE_SHARED) != 0) {
47505d05c7Sgtb 	    prf_data_t new_data;
48505d05c7Sgtb 	    new_data = profile_make_prf_data(file->data->filespec);
49505d05c7Sgtb 	    if (new_data == NULL) {
50505d05c7Sgtb 		retval = ENOMEM;
51505d05c7Sgtb 	    } else {
52505d05c7Sgtb 		retval = k5_mutex_init(&new_data->lock);
53505d05c7Sgtb 		if (retval == 0) {
54505d05c7Sgtb 		    new_data->root = NULL;
55505d05c7Sgtb 		    new_data->flags = file->data->flags & ~PROFILE_FILE_SHARED;
56505d05c7Sgtb 		    new_data->timestamp = 0;
57505d05c7Sgtb 		    new_data->upd_serial = file->data->upd_serial;
58505d05c7Sgtb 		}
59505d05c7Sgtb 	    }
60505d05c7Sgtb 
61505d05c7Sgtb 	    if (retval != 0) {
62505d05c7Sgtb 		profile_unlock_global();
63505d05c7Sgtb 		free(new_data);
64505d05c7Sgtb 		return retval;
65505d05c7Sgtb 	    }
66505d05c7Sgtb 	    profile_dereference_data_locked(file->data);
67505d05c7Sgtb 	    file->data = new_data;
68505d05c7Sgtb 	}
69505d05c7Sgtb 
70505d05c7Sgtb 	profile_unlock_global();
717c478bd9Sstevel@tonic-gate 	retval = profile_update_file(file);
72505d05c7Sgtb 
737c478bd9Sstevel@tonic-gate 	return retval;
747c478bd9Sstevel@tonic-gate }
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 
77*1da57d55SToomas Soome /*
78*1da57d55SToomas Soome  * Delete or update a particular child node
79*1da57d55SToomas Soome  *
807c478bd9Sstevel@tonic-gate  * ADL - 2/23/99, rewritten TYT 2/25/99
817c478bd9Sstevel@tonic-gate  */
82505d05c7Sgtb errcode_t KRB5_CALLCONV
profile_update_relation(profile_t profile,const char ** names,const char * old_value,const char * new_value)83505d05c7Sgtb profile_update_relation(profile_t profile, const char **names,
84505d05c7Sgtb 			const char *old_value, const char *new_value)
85*1da57d55SToomas Soome {
867c478bd9Sstevel@tonic-gate 	errcode_t	retval;
877c478bd9Sstevel@tonic-gate 	struct profile_node *section, *node;
887c478bd9Sstevel@tonic-gate 	void		*state;
897c478bd9Sstevel@tonic-gate 	const char	**cpp;
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	retval = rw_setup(profile);
927c478bd9Sstevel@tonic-gate 	if (retval)
937c478bd9Sstevel@tonic-gate 		return retval;
94*1da57d55SToomas Soome 
957c478bd9Sstevel@tonic-gate 	if (names == 0 || names[0] == 0 || names[1] == 0)
967c478bd9Sstevel@tonic-gate 		return PROF_BAD_NAMESET;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	if (!old_value || !*old_value)
997c478bd9Sstevel@tonic-gate 		return PROF_EINVAL;
1007c478bd9Sstevel@tonic-gate 
101505d05c7Sgtb 	retval = k5_mutex_lock(&profile->first_file->data->lock);
102505d05c7Sgtb 	if (retval)
103505d05c7Sgtb 	    return retval;
104505d05c7Sgtb 	section = profile->first_file->data->root;
1057c478bd9Sstevel@tonic-gate 	for (cpp = names; cpp[1]; cpp++) {
1067c478bd9Sstevel@tonic-gate 		state = 0;
1077c478bd9Sstevel@tonic-gate 		retval = profile_find_node(section, *cpp, 0, 1,
1087c478bd9Sstevel@tonic-gate 					   &state, &section);
109505d05c7Sgtb 		if (retval) {
110505d05c7Sgtb 		    k5_mutex_unlock(&profile->first_file->data->lock);
111505d05c7Sgtb 		    return retval;
112505d05c7Sgtb 		}
1137c478bd9Sstevel@tonic-gate 	}
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	state = 0;
1167c478bd9Sstevel@tonic-gate 	retval = profile_find_node(section, *cpp, old_value, 0, &state, &node);
117505d05c7Sgtb 	if (retval == 0) {
118505d05c7Sgtb 	    if (new_value)
1197c478bd9Sstevel@tonic-gate 		retval = profile_set_relation_value(node, new_value);
120505d05c7Sgtb 	    else
1217c478bd9Sstevel@tonic-gate 		retval = profile_remove_node(node);
122505d05c7Sgtb 	}
123505d05c7Sgtb 	if (retval == 0)
124505d05c7Sgtb 	    profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
125505d05c7Sgtb 	k5_mutex_unlock(&profile->first_file->data->lock);
126*1da57d55SToomas Soome 
127505d05c7Sgtb 	return retval;
1287c478bd9Sstevel@tonic-gate }
1297c478bd9Sstevel@tonic-gate 
130*1da57d55SToomas Soome /*
1317c478bd9Sstevel@tonic-gate  * Clear a particular all of the relations with a specific name.
132*1da57d55SToomas Soome  *
1337c478bd9Sstevel@tonic-gate  * TYT - 2/25/99
1347c478bd9Sstevel@tonic-gate  */
135505d05c7Sgtb errcode_t KRB5_CALLCONV
profile_clear_relation(profile_t profile,const char ** names)136505d05c7Sgtb profile_clear_relation(profile_t profile, const char **names)
137*1da57d55SToomas Soome {
1387c478bd9Sstevel@tonic-gate 	errcode_t	retval;
1397c478bd9Sstevel@tonic-gate 	struct profile_node *section, *node;
1407c478bd9Sstevel@tonic-gate 	void		*state;
1417c478bd9Sstevel@tonic-gate 	const char	**cpp;
142505d05c7Sgtb 
1437c478bd9Sstevel@tonic-gate 	retval = rw_setup(profile);
1447c478bd9Sstevel@tonic-gate 	if (retval)
1457c478bd9Sstevel@tonic-gate 		return retval;
146*1da57d55SToomas Soome 
1477c478bd9Sstevel@tonic-gate 	if (names == 0 || names[0] == 0 || names[1] == 0)
1487c478bd9Sstevel@tonic-gate 		return PROF_BAD_NAMESET;
1497c478bd9Sstevel@tonic-gate 
150505d05c7Sgtb 	section = profile->first_file->data->root;
1517c478bd9Sstevel@tonic-gate 	for (cpp = names; cpp[1]; cpp++) {
1527c478bd9Sstevel@tonic-gate 		state = 0;
1537c478bd9Sstevel@tonic-gate 		retval = profile_find_node(section, *cpp, 0, 1,
1547c478bd9Sstevel@tonic-gate 					   &state, &section);
1557c478bd9Sstevel@tonic-gate 		if (retval)
1567c478bd9Sstevel@tonic-gate 			return retval;
1577c478bd9Sstevel@tonic-gate 	}
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	state = 0;
1607c478bd9Sstevel@tonic-gate 	do {
1617c478bd9Sstevel@tonic-gate 		retval = profile_find_node(section, *cpp, 0, 0, &state, &node);
1627c478bd9Sstevel@tonic-gate 		if (retval)
1637c478bd9Sstevel@tonic-gate 			return retval;
1647c478bd9Sstevel@tonic-gate 		retval = profile_remove_node(node);
1657c478bd9Sstevel@tonic-gate 		if (retval)
1667c478bd9Sstevel@tonic-gate 			return retval;
1677c478bd9Sstevel@tonic-gate 	} while (state);
1687c478bd9Sstevel@tonic-gate 
169505d05c7Sgtb 	profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
170*1da57d55SToomas Soome 
1717c478bd9Sstevel@tonic-gate 	return 0;
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate 
174*1da57d55SToomas Soome /*
1757c478bd9Sstevel@tonic-gate  * Rename a particular section; if the new_section name is NULL,
1767c478bd9Sstevel@tonic-gate  * delete it.
177*1da57d55SToomas Soome  *
1787c478bd9Sstevel@tonic-gate  * ADL - 2/23/99, rewritten TYT 2/25/99
1797c478bd9Sstevel@tonic-gate  */
180505d05c7Sgtb errcode_t KRB5_CALLCONV
profile_rename_section(profile_t profile,const char ** names,const char * new_name)181505d05c7Sgtb profile_rename_section(profile_t profile, const char **names,
182505d05c7Sgtb 		       const char *new_name)
183*1da57d55SToomas Soome {
1847c478bd9Sstevel@tonic-gate 	errcode_t	retval;
1857c478bd9Sstevel@tonic-gate 	struct profile_node *section, *node;
1867c478bd9Sstevel@tonic-gate 	void		*state;
1877c478bd9Sstevel@tonic-gate 	const char	**cpp;
188*1da57d55SToomas Soome 
1897c478bd9Sstevel@tonic-gate 	retval = rw_setup(profile);
1907c478bd9Sstevel@tonic-gate 	if (retval)
1917c478bd9Sstevel@tonic-gate 		return retval;
192*1da57d55SToomas Soome 
1937c478bd9Sstevel@tonic-gate 	if (names == 0 || names[0] == 0 || names[1] == 0)
1947c478bd9Sstevel@tonic-gate 		return PROF_BAD_NAMESET;
1957c478bd9Sstevel@tonic-gate 
196505d05c7Sgtb 	retval = k5_mutex_lock(&profile->first_file->data->lock);
197505d05c7Sgtb 	if (retval)
198505d05c7Sgtb 	    return retval;
199505d05c7Sgtb 	section = profile->first_file->data->root;
2007c478bd9Sstevel@tonic-gate 	for (cpp = names; cpp[1]; cpp++) {
2017c478bd9Sstevel@tonic-gate 		state = 0;
2027c478bd9Sstevel@tonic-gate 		retval = profile_find_node(section, *cpp, 0, 1,
2037c478bd9Sstevel@tonic-gate 					   &state, &section);
204505d05c7Sgtb 		if (retval) {
205505d05c7Sgtb 		    k5_mutex_unlock(&profile->first_file->data->lock);
206505d05c7Sgtb 		    return retval;
207505d05c7Sgtb 		}
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	state = 0;
2117c478bd9Sstevel@tonic-gate 	retval = profile_find_node(section, *cpp, 0, 1, &state, &node);
212505d05c7Sgtb 	if (retval == 0) {
213505d05c7Sgtb 	    if (new_name)
2147c478bd9Sstevel@tonic-gate 		retval = profile_rename_node(node, new_name);
215505d05c7Sgtb 	    else
2167c478bd9Sstevel@tonic-gate 		retval = profile_remove_node(node);
217505d05c7Sgtb 	}
218505d05c7Sgtb 	if (retval == 0)
219505d05c7Sgtb 	    profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
220505d05c7Sgtb 	k5_mutex_unlock(&profile->first_file->data->lock);
221505d05c7Sgtb 	return retval;
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate /*
2257c478bd9Sstevel@tonic-gate  * Insert a new relation.  If the new_value argument is NULL, then
2267c478bd9Sstevel@tonic-gate  * create a new section instead.
2277c478bd9Sstevel@tonic-gate  *
2287c478bd9Sstevel@tonic-gate  * Note: if the intermediate sections do not exist, this function will
2297c478bd9Sstevel@tonic-gate  * automatically create them.
2307c478bd9Sstevel@tonic-gate  *
2317c478bd9Sstevel@tonic-gate  * ADL - 2/23/99, rewritten TYT 2/25/99
2327c478bd9Sstevel@tonic-gate  */
233505d05c7Sgtb errcode_t KRB5_CALLCONV
profile_add_relation(profile_t profile,const char ** names,const char * new_value)234505d05c7Sgtb profile_add_relation(profile_t profile, const char **names,
235505d05c7Sgtb 		     const char *new_value)
2367c478bd9Sstevel@tonic-gate {
2377c478bd9Sstevel@tonic-gate 	errcode_t	retval;
2387c478bd9Sstevel@tonic-gate     	struct profile_node *section;
2397c478bd9Sstevel@tonic-gate 	const char 	**cpp;
2407c478bd9Sstevel@tonic-gate 	void		*state;
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	retval = rw_setup(profile);
2437c478bd9Sstevel@tonic-gate 	if (retval)
2447c478bd9Sstevel@tonic-gate 		return retval;
245*1da57d55SToomas Soome 
2467c478bd9Sstevel@tonic-gate 	if (names == 0 || names[0] == 0 || names[1] == 0)
2477c478bd9Sstevel@tonic-gate 		return PROF_BAD_NAMESET;
2487c478bd9Sstevel@tonic-gate 
249505d05c7Sgtb 	retval = k5_mutex_lock(&profile->first_file->data->lock);
250505d05c7Sgtb 	if (retval)
251505d05c7Sgtb 	    return retval;
252505d05c7Sgtb 	section = profile->first_file->data->root;
2537c478bd9Sstevel@tonic-gate 	for (cpp = names; cpp[1]; cpp++) {
2547c478bd9Sstevel@tonic-gate 		state = 0;
2557c478bd9Sstevel@tonic-gate 		retval = profile_find_node(section, *cpp, 0, 1,
2567c478bd9Sstevel@tonic-gate 					   &state, &section);
2577c478bd9Sstevel@tonic-gate 		if (retval == PROF_NO_SECTION)
2587c478bd9Sstevel@tonic-gate 			retval = profile_add_node(section, *cpp, 0, &section);
259505d05c7Sgtb 		if (retval) {
260505d05c7Sgtb 		    k5_mutex_unlock(&profile->first_file->data->lock);
261505d05c7Sgtb 		    return retval;
262505d05c7Sgtb 		}
2637c478bd9Sstevel@tonic-gate 	}
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	if (new_value == 0) {
2667c478bd9Sstevel@tonic-gate 		retval = profile_find_node(section, *cpp, 0, 1, &state, 0);
267505d05c7Sgtb 		if (retval == 0) {
268505d05c7Sgtb 		    k5_mutex_unlock(&profile->first_file->data->lock);
269505d05c7Sgtb 		    return PROF_EXISTS;
270505d05c7Sgtb 		} else if (retval != PROF_NO_SECTION) {
271505d05c7Sgtb 		    k5_mutex_unlock(&profile->first_file->data->lock);
272505d05c7Sgtb 		    return retval;
273505d05c7Sgtb 		}
2747c478bd9Sstevel@tonic-gate 	}
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	retval = profile_add_node(section, *cpp, new_value, 0);
277505d05c7Sgtb 	if (retval) {
278505d05c7Sgtb 	    k5_mutex_unlock(&profile->first_file->data->lock);
279505d05c7Sgtb 	    return retval;
280505d05c7Sgtb 	}
2817c478bd9Sstevel@tonic-gate 
282505d05c7Sgtb 	profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
283505d05c7Sgtb 	k5_mutex_unlock(&profile->first_file->data->lock);
2847c478bd9Sstevel@tonic-gate 	return 0;
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate 
287