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 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 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, §ion); 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 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, §ion); 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 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, §ion); 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 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, §ion); 272 if (retval == PROF_NO_SECTION) 273 retval = profile_add_node(section, *cpp, NULL, 0, §ion); 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