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