/daten/src/linux-2.4.27-rsbac-v1.2.3/rsbac/adf/daz/dazuko_xp.c

Go to the documentation of this file.
00001 /* DazukoXP. Allow cross platform file access control for 3rd-party applications. 00002 Written by John Ogness <jogness@antivir.de> 00003 00004 Copyright (c) 2002-2004 H+BEDV Datentechnik GmbH 00005 All rights reserved. 00006 00007 Redistribution and use in source and binary forms, with or without 00008 modification, are permitted provided that the following conditions 00009 are met: 00010 00011 1. Redistributions of source code must retain the above copyright notice, 00012 this list of conditions and the following disclaimer. 00013 00014 2. Redistributions in binary form must reproduce the above copyright notice, 00015 this list of conditions and the following disclaimer in the documentation 00016 and/or other materials provided with the distribution. 00017 00018 3. Neither the name of Dazuko nor the names of its contributors may be used 00019 to endorse or promote products derived from this software without specific 00020 prior written permission. 00021 00022 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00023 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00024 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00025 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00026 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00027 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00028 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00029 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00030 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00031 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 POSSIBILITY OF SUCH DAMAGE. 00033 */ 00034 00035 #include "dazuko_platform.h" 00036 00037 #include "dazuko_xp.h" 00038 #include "dazukoio.h" 00039 #include "dazuko_call.h" 00040 00041 #define NUM_SLOT_LISTS 5 00042 #define NUM_SLOTS 25 00043 00044 #define SCAN_ON_OPEN (access_mask & DAZUKO_ON_OPEN) 00045 #define SCAN_ON_CLOSE (access_mask & DAZUKO_ON_CLOSE) 00046 #define SCAN_ON_EXEC (access_mask & DAZUKO_ON_EXEC) 00047 #define SCAN_ON_CLOSE_MODIFIED (access_mask & DAZUKO_ON_CLOSE_MODIFIED) 00048 00049 struct path 00050 { 00051 /* A node in a linked list of paths. Used 00052 * for the include and exclude lists. */ 00053 00054 struct path *next; 00055 int len; 00056 char path[1]; /* this MUST be at the end of the struct */ 00057 }; 00058 00059 struct hash 00060 { 00061 /* A node in a linked list of filenames. 00062 * Used for the list of files to be 00063 * scanned on close. */ 00064 00065 struct hash *next; 00066 struct xp_file file; 00067 int dirty; 00068 int namelen; 00069 char name[1]; /* this MUST be at the end of the struct */ 00070 }; 00071 00072 struct daemon_id 00073 { 00074 int unique; 00075 struct xp_daemon_id *xp_id; 00076 }; 00077 00078 struct slot 00079 { 00080 /* A representation of a daemon. It holds 00081 * all information about the daemon, the 00082 * file that is scanned, and the state of 00083 * the scanning process. */ 00084 00085 int id; 00086 struct daemon_id did; /* identifier for our daemon */ 00087 int write_mode; 00088 int state; 00089 int response; 00090 int event; 00091 int filenamelength; /* not including terminator */ 00092 char *filename; 00093 struct event_properties event_p; 00094 struct file_properties file_p; 00095 struct xp_mutex mutex; 00096 }; 00097 00098 struct slot_list 00099 { 00100 struct xp_atomic use_count; 00101 struct slot slots[NUM_SLOTS]; 00102 char reg_name[1]; /* this MUST be at the end of the struct */ 00103 }; 00104 00105 struct slot_list_container 00106 { 00107 struct slot_list *slot_list; 00108 struct xp_mutex mutex; 00109 }; 00110 00111 struct one_slot_state_not_condition_param 00112 { 00113 struct slot *slot; 00114 int state; 00115 }; 00116 00117 struct two_slot_state_not_condition_param 00118 { 00119 struct slot *slot1; 00120 int state1; 00121 struct slot *slot2; 00122 int state2; 00123 }; 00124 00125 struct get_ready_slot_condition_param 00126 { 00127 struct slot *slot; 00128 struct slot_list *slotlist; 00129 }; 00130 00131 static int unique_count = 1; 00132 static char access_mask = 7; 00133 static struct slot_list_container slot_lists[NUM_SLOT_LISTS]; 00134 static struct path *incl_paths = NULL; 00135 static struct path *excl_paths = NULL; 00136 static struct hash *hash = NULL; 00137 static struct xp_rwlock lock_hash; 00138 static struct xp_rwlock lock_lists; 00139 static struct xp_atomic active; 00140 static struct xp_mutex mutex_unique_count; 00141 00142 static struct xp_queue wait_kernel_waiting_for_free_slot; 00143 static struct xp_queue wait_daemon_waiting_for_work; 00144 static struct xp_queue wait_kernel_waiting_while_daemon_works; 00145 static struct xp_queue wait_daemon_waiting_for_free; 00146 00147 00148 int dazuko_vsnprintf(char *str, size_t size, const char *format, va_list ap) 00149 { 00150 char *target; 00151 const char *end; 00152 int overflow = 0; 00153 char number_buffer[32]; /* 32 should be enough to hold any number, right? */ 00154 const char *s; 00155 00156 if (str == NULL || size < 1 || format == NULL) 00157 return -1; 00158 00159 target = str; 00160 end = (target + size) - 1; 00161 00162 #define DAZUKO_VSNPRINTF_PRINTSTRING \ 00163 for ( ; *s ; s++) \ 00164 { \ 00165 if (target == end) \ 00166 { \ 00167 overflow = 1; \ 00168 goto dazuko_vsnprintf_out; \ 00169 } \ 00170 *target = *s; \ 00171 target++; \ 00172 } 00173 00174 for ( ; *format ; format++) 00175 { 00176 if (target == end) 00177 { 00178 overflow = 1; 00179 goto dazuko_vsnprintf_out; 00180 } 00181 00182 if (*format == '%') 00183 { 00184 format++; 00185 00186 switch (*format) 00187 { 00188 case 's': /* %s */ 00189 s = va_arg(ap, char *); 00190 if (s == NULL) 00191 s = "(null)"; 00192 DAZUKO_VSNPRINTF_PRINTSTRING 00193 break; 00194 00195 case 'd': /* %d */ 00196 sprintf(number_buffer, "%d", va_arg(ap, int)); 00197 s = number_buffer; 00198 DAZUKO_VSNPRINTF_PRINTSTRING 00199 break; 00200 00201 case 'c': /* %c */ 00202 *target = va_arg(ap, int); 00203 target++; 00204 break; 00205 00206 case 'l': /* %lu */ 00207 format++; 00208 if (*format != 'u') 00209 { 00210 /* print error message */ 00211 goto dazuko_vsnprintf_out; 00212 } 00213 sprintf(number_buffer, "%lu", va_arg(ap, unsigned long)); 00214 s = number_buffer; 00215 DAZUKO_VSNPRINTF_PRINTSTRING 00216 break; 00217 00218 case '0': /* %02x */ 00219 format++; 00220 if (*format != '2') 00221 { 00222 /* print error message */ 00223 goto dazuko_vsnprintf_out; 00224 } 00225 format++; 00226 if (*format != 'x') 00227 { 00228 /* print error message */ 00229 goto dazuko_vsnprintf_out; 00230 } 00231 sprintf(number_buffer, "%02x", va_arg(ap, int)); 00232 s = number_buffer; 00233 DAZUKO_VSNPRINTF_PRINTSTRING 00234 break; 00235 00236 default: 00237 /* print error message */ 00238 goto dazuko_vsnprintf_out; 00239 } 00240 } 00241 else 00242 { 00243 *target = *format; 00244 target++; 00245 } 00246 } 00247 00248 dazuko_vsnprintf_out: 00249 00250 *target = 0; 00251 00252 /* We are returning what we've written. If there was an 00253 * overflow, the returned value will match "size" rather 00254 * than being less than "size" 00255 */ 00256 00257 return ((target - str) + overflow); 00258 } 00259 00260 int dazuko_snprintf(char *str, size_t size, const char *format, ...) 00261 { 00262 va_list ap; 00263 int ret; 00264 00265 va_start(ap, format); 00266 ret = dazuko_vsnprintf(str, size, format, ap); 00267 va_end(ap); 00268 00269 return ret; 00270 } 00271 00272 inline void dazuko_bzero(void *p, int len) 00273 { 00274 /* "zero out" len bytes starting with p */ 00275 00276 char *ptr = (char *)p; 00277 00278 while (len--) 00279 *ptr++ = 0; 00280 } 00281 00282 static inline int dazuko_get_new_unique(void) 00283 { 00284 int unique; 00285 00286 /* DOWN */ 00287 call_xp_down(&mutex_unique_count); 00288 00289 unique = unique_count; 00290 unique_count++; 00291 00292 call_xp_up(&mutex_unique_count); 00293 /* UP */ 00294 00295 return unique; 00296 } 00297 00298 static inline int dazuko_slot_state(struct slot *s) 00299 { 00300 int state; 00301 00302 /* DOWN */ 00303 if (call_xp_down(&(s->mutex)) != 0) 00304 return XP_ERROR_INTERRUPT; 00305 00306 state = s->state; 00307 00308 call_xp_up(&(s->mutex)); 00309 /* UP */ 00310 00311 return state; 00312 } 00313 00314 static int one_slot_state_not_condition(void *param) 00315 { 00316 return (dazuko_slot_state(((struct one_slot_state_not_condition_param *)param)->slot) 00317 != ((struct one_slot_state_not_condition_param *)param)->state); 00318 } 00319 00320 static int two_slot_state_not_condition(void *param) 00321 { 00322 return (dazuko_slot_state(((struct two_slot_state_not_condition_param *)param)->slot1) 00323 != ((struct two_slot_state_not_condition_param *)param)->state1 00324 && dazuko_slot_state(((struct two_slot_state_not_condition_param *)param)->slot2) 00325 != ((struct two_slot_state_not_condition_param *)param)->state2); 00326 } 00327 00328 static inline int __dazuko_change_slot_state(struct slot *s, int from_state, int to_state) 00329 { 00330 /* Make a predicted state transition. We fail if it 00331 * is an unpredicted change. We can ALWAYS go to the 00332 * to_state if it is the same as from_state. Not SMP safe! */ 00333 00334 if (to_state != from_state) 00335 { 00336 /* make sure this is a predicted transition and there 00337 * is a daemon on this slot (unique != 0)*/ 00338 if (s->state != from_state || s->did.unique == 0) 00339 return 0; 00340 } 00341 00342 s->state = to_state; 00343 00344 /* handle appropriate wake_up's for basic 00345 * state changes */ 00346 00347 if (to_state == DAZUKO_READY) 00348 { 00349 call_xp_notify(&wait_kernel_waiting_for_free_slot); 00350 } 00351 else if (to_state == DAZUKO_FREE) 00352 { 00353 call_xp_notify(&wait_kernel_waiting_while_daemon_works); 00354 call_xp_notify(&wait_daemon_waiting_for_free); 00355 } 00356 00357 return 1; 00358 } 00359 00360 static int dazuko_change_slot_state(struct slot *s, int from_state, int to_state, int release) 00361 { 00362 /* SMP safe version of __dazuko_change_slot_state(). 00363 * This should only be used if we haven't 00364 * already aquired slot.mutex. Use this function 00365 * with CAUTION, since the mutex may or may not 00366 * be released depending on the return value AND 00367 * on the value of the "release" argument. */ 00368 00369 int success; 00370 00371 /* if we are interrupted, report the state as unpredicted */ 00372 /* DOWN */ 00373 if (call_xp_down(&(s->mutex)) != 0) 00374 return 0; 00375 00376 success = __dazuko_change_slot_state(s, from_state, to_state); 00377 00378 /* the mutex is released if the state change was 00379 * unpredicted or if the called wants it released */ 00380 if (!success || release) 00381 call_xp_up(&(s->mutex)); 00382 /* UP */ 00383 return success; 00384 } 00385 00386 static struct slot * _dazuko_find_slot(struct daemon_id *did, int release, struct slot_list *sl) 00387 { 00388 /* Find the first slot with the same given 00389 * pid number. SMP safe. Use this function 00390 * with CAUTION, since the mutex may or may not 00391 * be released depending on the return value AND 00392 * on the value of the "release" argument. */ 00393 00394 int i; 00395 struct slot *s = NULL; 00396 00397 if (sl == NULL) 00398 { 00399 call_xp_print("dazuko: invalid slot_list given (bug!)\n"); 00400 return NULL; 00401 } 00402 00403 for (i=0 ; i<NUM_SLOTS ; i++) 00404 { 00405 s = &(sl->slots[i]); 00406 /* DOWN */ 00407 /* if we are interrupted, we say that no 00408 * slot was found */ 00409 if (call_xp_down(&(s->mutex)) != 0) 00410 return NULL; 00411 00412 if (did == NULL) 00413 { 00414 /* we are looking for an empty slot */ 00415 if (s->did.unique == 0 && s->did.xp_id == NULL) 00416 { 00417 /* we release the mutex only if the 00418 * called wanted us to */ 00419 if (release) 00420 call_xp_up(&(s->mutex)); 00421 /* UP */ 00422 return s; 00423 } 00424 } 00425 else if (s->did.unique == 0 && s->did.xp_id == NULL) 00426 { 00427 /* this slot is emtpy, so it can't match */ 00428 00429 /* do nothing */ 00430 } 00431 /* xp_id's must match! */ 00432 else if (call_xp_id_compare(s->did.xp_id, did->xp_id) == 0) 00433 { 00434 /* unique's must also match (unless unique is negative, 00435 * in which case we will trust xp_id) */ 00436 if (did->unique < 0 || (s->did.unique == did->unique)) 00437 { 00438 /* we release the mutex only if the 00439 * called wanted us to */ 00440 if (release) 00441 call_xp_up(&(s->mutex)); 00442 /* UP */ 00443 return s; 00444 } 00445 } 00446 00447 call_xp_up(&(s->mutex)); 00448 /* UP */ 00449 } 00450 00451 return NULL; 00452 } 00453 00454 static struct slot * dazuko_find_slot_and_slotlist(struct daemon_id *did, int release, struct slot_list *slist, struct slot_list **sl_result) 00455 { 00456 struct slot *s; 00457 int i; 00458 struct slot_list *sl; 00459 00460 if (slist == NULL) 00461 { 00462 for (i=0 ; i<NUM_SLOT_LISTS ; i++) 00463 { 00464 /* DOWN */ 00465 /* if we are interrupted, we say that no 00466 * slot was found */ 00467 if (call_xp_down(&(slot_lists[i].mutex)) != 0) 00468 return NULL; 00469 00470 sl = slot_lists[i].slot_list; 00471 00472 call_xp_up(&(slot_lists[i].mutex)); 00473 /* UP */ 00474 00475 if (sl != NULL) 00476 { 00477 s = _dazuko_find_slot(did, release, sl); 00478 if (s != NULL) 00479 { 00480 /* set the current slot_list */ 00481 if (sl_result != NULL) 00482 *sl_result = sl; 00483 00484 return s; 00485 } 00486 } 00487 } 00488 } 00489 else 00490 { 00491 return _dazuko_find_slot(did, release, slist); 00492 } 00493 00494 return NULL; 00495 } 00496 00497 static inline struct slot * dazuko_find_slot(struct daemon_id *did, int release, struct slot_list *slist) 00498 { 00499 return dazuko_find_slot_and_slotlist(did, release, slist, NULL); 00500 } 00501 00502 static int dazuko_insert_path_fs(struct path **list, char *fs_path, int fs_len) 00503 { 00504 /* Create a new struct path structure and insert it 00505 * into the linked list given (list argument). 00506 * The fs_len argument is to help speed things 00507 * up so we don't have to calculate the length 00508 * of fs_path. */ 00509 00510 struct path *newitem; 00511 struct path *tmp; 00512 00513 if (fs_path == NULL || fs_len < 1) 00514 return XP_ERROR_INVALID; 00515 00516 /* we want only absolute paths */ 00517 if (!call_xp_is_absolute_path(fs_path)) 00518 return XP_ERROR_INVALID; 00519 00520 /* create a new struct path structure making room for path also */ 00521 newitem = (struct path *)call_xp_malloc(sizeof(struct path) + fs_len); 00522 if (!newitem) 00523 return XP_ERROR_FAULT; 00524 00525 /* fs_path is already in kernelspace */ 00526 memcpy(newitem->path, fs_path, fs_len); 00527 00528 newitem->path[fs_len] = 0; 00529 00530 while (newitem->path[fs_len-1] == 0) 00531 { 00532 fs_len--; 00533 if (fs_len == 0) 00534 break; 00535 } 00536 00537 if (fs_len < 1) 00538 { 00539 call_xp_free(newitem); 00540 return XP_ERROR_INVALID; 00541 } 00542 00543 newitem->len = fs_len; 00544 00545 /* check if this path already exists in the list */ 00546 for (tmp=*list ; tmp ; tmp=tmp->next) 00547 { 00548 if (newitem->len == tmp->len) 00549 { 00550 if (memcmp(newitem->path, tmp->path, tmp->len) == 0) 00551 { 00552 /* we already have this path */ 00553 00554 call_xp_free(newitem); 00555 00556 return 0; 00557 } 00558 } 00559 } 00560 00561 DPRINT(("dazuko: adding %s %s\n", (list == &incl_paths) ? "incl" : "excl", newitem->path)); 00562 00563 /* add struct path to head of linked list */ 00564 /* LOCK */ 00565 call_xp_write_lock(&lock_lists); 00566 newitem->next = *list; 00567 *list = newitem; 00568 call_xp_write_unlock(&lock_lists); 00569 /* UNLOCK */ 00570 00571 return 0; 00572 } 00573 00574 static void dazuko_remove_all_hash(void) 00575 { 00576 /* Empty the hash linked list. */ 00577 00578 struct hash *tmp; 00579 00580 /* LOCK */ 00581 call_xp_write_lock(&lock_hash); 00582 while (hash) 00583 { 00584 tmp = hash; 00585 hash = hash->next; 00586 00587 DPRINT(("dazuko: removing hash %s\n", tmp->name)); 00588 00589 call_xp_free(tmp); 00590 } 00591 call_xp_write_unlock(&lock_hash); 00592 /* UNLOCK */ 00593 } 00594 00595 static void dazuko_remove_all_paths(void) 00596 { 00597 /* Empty both include and exclude struct path 00598 * linked lists. */ 00599 00600 struct path *tmp; 00601 00602 /* LOCK */ 00603 call_xp_write_lock(&lock_lists); 00604 00605 /* empty include paths list */ 00606 while (incl_paths) 00607 { 00608 tmp = incl_paths; 00609 incl_paths = incl_paths->next; 00610 00611 DPRINT(("dazuko: removing incl %s\n", tmp->path)); 00612 00613 call_xp_free(tmp); 00614 } 00615 00616 /* empty exclude paths list */ 00617 while (excl_paths) 00618 { 00619 tmp = excl_paths; 00620 excl_paths = excl_paths->next; 00621 00622 DPRINT(("dazuko: removing excl %s\n", tmp->path)); 00623 00624 call_xp_free(tmp); 00625 } 00626 00627 call_xp_write_unlock(&lock_lists); 00628 /* UNLOCK */ 00629 } 00630 00631 static int _dazuko_unregister_daemon(struct daemon_id *did) 00632 { 00633 /* We unregister the daemon by finding the 00634 * slot with the same slot->pid as the the 00635 * current process id, the daemon. */ 00636 00637 struct slot *s; 00638 struct slot_list *sl; 00639 00640 DPRINT(("dazuko: dazuko_unregister_daemon() [%d]\n", did->unique)); 00641 00642 /* find our slot and hold the mutex 00643 * if we find it */ 00644 /* DOWN? */ 00645 s = dazuko_find_slot_and_slotlist(did, 0, NULL, &sl); 00646 00647 if (s == NULL) 00648 { 00649 /* this daemon was not registered */ 00650 return 0; 00651 } 00652 00653 /* DOWN */ 00654 00655 /* clearing the unique and pid makes the slot available */ 00656 s->did.unique = 0; 00657 call_xp_id_free(s->did.xp_id); 00658 s->did.xp_id = NULL; 00659 00660 /* reset slot state */ 00661 __dazuko_change_slot_state(s, DAZUKO_FREE, DAZUKO_FREE); 00662 00663 call_xp_atomic_dec(&(sl->use_count)); 00664 00665 call_xp_up(&(s->mutex)); 00666 /* UP */ 00667 00668 /* active should always be positive here, but 00669 * let's check just to be sure. ;) */ 00670 if (call_xp_atomic_read(&active) > 0) 00671 { 00672 /* active and the kernel usage counter 00673 * should always reflect how many daemons 00674 * are active */ 00675 00676 call_xp_atomic_dec(&active); 00677 } 00678 else 00679 { 00680 call_xp_print("dazuko: active count error (possible bug)\n"); 00681 } 00682 00683 /* Wake up any kernel processes that are 00684 * waiting for an available slot. Remove 00685 * all the include and exclude paths 00686 * if there are no more daemons */ 00687 00688 if (call_xp_atomic_read(&active) == 0) 00689 { 00690 /* clear out include and exclude paths */ 00691 /* are we sure we want to do this? */ 00692 dazuko_remove_all_paths(); 00693 00694 /* clear out hash nodes */ 00695 dazuko_remove_all_hash(); 00696 } 00697 00698 call_xp_notify(&wait_kernel_waiting_for_free_slot); 00699 call_xp_notify(&wait_kernel_waiting_while_daemon_works); 00700 00701 return 0; 00702 } 00703 00704 int dazuko_unregister_daemon(struct xp_daemon_id *xp_id) 00705 { 00706 struct daemon_id did; 00707 int ret; 00708 00709 if (xp_id == NULL) 00710 return 0; 00711 00712 did.unique = -1; 00713 did.xp_id = call_xp_id_copy(xp_id); 00714 00715 ret = _dazuko_unregister_daemon(&did); 00716 00717 call_xp_id_free(did.xp_id); 00718 00719 return ret; 00720 } 00721 00722 static inline int dazuko_state_error(struct slot *s, int current_state) 00723 { 00724 if (dazuko_change_slot_state(s, current_state, DAZUKO_BROKEN, 1)) 00725 { 00726 call_xp_notify(&wait_kernel_waiting_for_free_slot); 00727 call_xp_notify(&wait_kernel_waiting_while_daemon_works); 00728 } 00729 00730 return 0; 00731 } 00732 00733 static int dazuko_register_daemon(struct daemon_id *did, const char *reg_name, int string_length, int write_mode) 00734 { 00735 const char *p1; 00736 char *p2; 00737 struct slot *s; 00738 struct slot_list *sl; 00739 int i; 00740 00741 DPRINT(("dazuko: dazuko_register_daemon() [%d]\n", did->unique)); 00742 00743 if (did == NULL || reg_name == NULL) 00744 return XP_ERROR_PERMISSION; 00745 00746 s = dazuko_find_slot(did, 1, NULL); 00747 00748 if (s != NULL) 00749 { 00750 /* We are already registered! */ 00751 00752 call_xp_print("dazuko: daemon %d already assigned to slot[%d]\n", did->unique, s->id); 00753 00754 return XP_ERROR_PERMISSION; 00755 } 00756 00757 /* Find the slot_list with the matching name. */ 00758 00759 for (i=0 ; i<NUM_SLOT_LISTS ; i++) 00760 { 00761 /* DOWN */ 00762 /* if we are interrupted, we say that it 00763 * was interrupted */ 00764 if (call_xp_down(&(slot_lists[i].mutex)) != 0) 00765 return XP_ERROR_INTERRUPT; 00766 00767 sl = slot_lists[i].slot_list; 00768 00769 call_xp_up(&(slot_lists[i].mutex)); 00770 /* UP */ 00771 00772 if (sl != NULL) 00773 { 00774 p1 = reg_name; 00775 p2 = sl->reg_name; 00776 00777 while (*p1 == *p2) 00778 { 00779 if (*p1 == 0) 00780 break; 00781 00782 p1++; 00783 p2++; 00784 } 00785 00786 if (*p1 == *p2) 00787 break; 00788 } 00789 } 00790 00791 if (i == NUM_SLOT_LISTS) 00792 { 00793 /* There is no slot_list with this name. We 00794 * need to make one. */ 00795 00796 sl = (struct slot_list *)call_xp_malloc(sizeof(struct slot_list) + string_length); 00797 if (!sl) 00798 return XP_ERROR_FAULT; 00799 00800 dazuko_bzero(sl, sizeof(struct slot_list) + string_length); 00801 call_xp_atomic_set(&(sl->use_count), 0); 00802 00803 p1 = reg_name; 00804 p2 = sl->reg_name; 00805 00806 while (*p1) 00807 { 00808 *p2 = *p1; 00809 00810 p1++; 00811 p2++; 00812 } 00813 *p2 = 0; 00814 00815 /* give each slot a unique id */ 00816 for (i=0 ; i<NUM_SLOTS ; i++) 00817 { 00818 sl->slots[i].id = i; 00819 call_xp_init_mutex(&(sl->slots[i].mutex)); 00820 } 00821 00822 /* we need to find an empty slot */ 00823 for (i=0 ; i<NUM_SLOT_LISTS ; i++) 00824 { 00825 /* DOWN */ 00826 /* if we are interrupted, we need to cleanup 00827 * and return error */ 00828 if (call_xp_down(&(slot_lists[i].mutex)) != 0) 00829 { 00830 call_xp_free(sl); 00831 return XP_ERROR_INTERRUPT; 00832 } 00833 00834 if (slot_lists[i].slot_list == NULL) 00835 { 00836 slot_lists[i].slot_list = sl; 00837 00838 call_xp_up(&(slot_lists[i].mutex)); 00839 /* UP */ 00840 break; 00841 } 00842 00843 call_xp_up(&(slot_lists[i].mutex)); 00844 /* UP */ 00845 } 00846 00847 if (i == NUM_SLOT_LISTS) 00848 { 00849 /* no empty slot :( */ 00850 call_xp_free(sl); 00851 return XP_ERROR_BUSY; 00852 } 00853 } 00854 00855 /* find an available slot and hold the mutex 00856 * if we find one */ 00857 /* DOWN? */ 00858 s = dazuko_find_slot(NULL, 0, sl); 00859 00860 if (s == NULL) 00861 return XP_ERROR_BUSY; 00862 00863 /* DOWN */ 00864 00865 /* We have found a slot, so increment the active 00866 * variable and the kernel module use counter. 00867 * The module counter will always reflect the 00868 * number of daemons. */ 00869 00870 call_xp_atomic_inc(&active); 00871 00872 /* get new unique id for this process */ 00873 did->unique = dazuko_get_new_unique(); 00874 00875 s->did.unique = did->unique; 00876 s->did.xp_id = call_xp_id_copy(did->xp_id); 00877 s->write_mode = write_mode; 00878 00879 call_xp_atomic_inc(&(sl->use_count)); 00880 00881 /* the daemon is registered, but not yet 00882 * ready to receive files */ 00883 __dazuko_change_slot_state(s, DAZUKO_FREE, DAZUKO_FREE); 00884 00885 DPRINT(("dazuko: slot[%d] assigned to daemon %d\n", s->id, s->did.unique)); 00886 00887 call_xp_up(&(s->mutex)); 00888 /* UP */ 00889 00890 return 0; 00891 } 00892 00893 static struct slot* dazuko_get_an_access(struct daemon_id *did) 00894 { 00895 /* The daemon is requesting a filename of a file 00896 * to scan. This code will wait until a filename 00897 * is available, or until we should be killed. 00898 * (killing is done if any errors occur as well 00899 * as when the user kills us) */ 00900 00901 /* If a slot is returned, it will be already locked! */ 00902 00903 int i; 00904 struct slot *s; 00905 struct one_slot_state_not_condition_param cond_p; 00906 00907 tryagain: 00908 /* find our slot */ 00909 s = dazuko_find_slot(did, 1, NULL); 00910 00911 if (s == NULL) 00912 { 00913 i = dazuko_register_daemon(did, "_COMPAT", 7, 1); 00914 if (i != 0) 00915 { 00916 call_xp_print("dazuko: unregistered daemon %d attempted to get access\n", did->unique); 00917 return NULL; 00918 } 00919 00920 s = dazuko_find_slot(did, 1, NULL); 00921 if (s == NULL) 00922 { 00923 call_xp_print("dazuko: unregistered daemon %d attempted to get access\n", did->unique); 00924 return NULL; 00925 } 00926 00927 call_xp_print("dazuko: warning: daemon %d is using a deprecated protocol\n", did->unique); 00928 } 00929 00930 /* the daemon is now ready to receive a file */ 00931 dazuko_change_slot_state(s, DAZUKO_READY, DAZUKO_READY, 1); 00932 00933 cond_p.slot = s; 00934 cond_p.state = DAZUKO_READY; 00935 if (call_xp_wait_until_condition(&wait_daemon_waiting_for_work, one_slot_state_not_condition, &cond_p, 1) != 0) 00936 { 00937 /* The user has issued an interrupt. 00938 * Return an error. The daemon should 00939 * unregister itself. */ 00940 00941 DPRINT(("dazuko: daemon %d killed while waiting for work\n", did->unique)); 00942 00943 if (dazuko_change_slot_state(s, DAZUKO_READY, DAZUKO_BROKEN, 1) || dazuko_change_slot_state(s, DAZUKO_WAITING, DAZUKO_BROKEN, 1)) 00944 { 00945 call_xp_notify(&wait_kernel_waiting_for_free_slot); 00946 call_xp_notify(&wait_kernel_waiting_while_daemon_works); 00947 } 00948 00949 return NULL; 00950 } 00951 00952 /* slot SHOULD now be in DAZUKO_WAITING state */ 00953 00954 /* we will be working with the slot, so 00955 * we need to lock it */ 00956 00957 /* DOWN? */ 00958 if (!dazuko_change_slot_state(s, DAZUKO_WAITING, DAZUKO_WORKING, 0)) 00959 { 00960 /* State transition error. Try again., */ 00961 00962 goto tryagain; 00963 } 00964 00965 /* DOWN */ 00966 00967 /* Slot IS in DAZUKO_WORKING state. Copy all the 00968 * necessary information to userspace structure. */ 00969 00970 /* IMPORTANT: slot is still locked! */ 00971 00972 return s; /* access is available */ 00973 } 00974 00975 static int dazuko_return_access(struct daemon_id *did, int response, struct slot *s) 00976 { 00977 /* The daemon has finished scanning a file 00978 * and has the response to give. The daemon's 00979 * slot should be in the DAZUKO_WORKING state. */ 00980 00981 struct one_slot_state_not_condition_param cond_p; 00982 00983 /* do we already have a slot? */ 00984 if (s == NULL) 00985 { 00986 /* find our slot */ 00987 s = dazuko_find_slot(did, 1, NULL); 00988 00989 if (s == NULL) 00990 { 00991 /* It appears the kernel isn't interested 00992 * in us or our response. It gave our slot away! */ 00993 00994 DPRINT(("dazuko: daemon %d unexpectedly lost slot\n", did->unique)); 00995 00996 return XP_ERROR_PERMISSION; 00997 } 00998 } 00999 01000 /* we will be writing into the slot, so we 01001 * need to lock it */ 01002 01003 /* DOWN? */ 01004 if (!dazuko_change_slot_state(s, DAZUKO_WORKING, DAZUKO_DONE, 0)) 01005 { 01006 /* The slot is in the wrong state. We will 01007 * assume the kernel has cancelled the file 01008 * access. */ 01009 01010 DPRINT(("dazuko: response from daemon %d on slot[%d] not needed\n", did->unique, s->id)); 01011 01012 return 0; 01013 } 01014 01015 /* DOWN */ 01016 01017 s->response = response; 01018 01019 call_xp_up(&(s->mutex)); 01020 /* UP */ 01021 01022 /* wake up any kernel processes that are 01023 * waiting for responses */ 01024 call_xp_notify(&wait_kernel_waiting_while_daemon_works); 01025 01026 cond_p.slot = s; 01027 cond_p.state = DAZUKO_DONE; 01028 if (call_xp_wait_until_condition(&wait_daemon_waiting_for_free, one_slot_state_not_condition, &cond_p, 1) != 0) 01029 { 01030 /* The user has issued an interrupt. 01031 * Return an error. The daemon should 01032 * unregister itself. */ 01033 01034 DPRINT(("dazuko: daemon %d killed while waiting for response acknowledgement\n", did->unique)); 01035 01036 return XP_ERROR_INTERRUPT; 01037 } 01038 01039 return 0; 01040 } 01041 01042 static inline int dazuko_isdigit(const char c) 01043 { 01044 return (c >= '0' && c <= '9'); 01045 } 01046 01047 static inline long dazuko_strtol(const char *string) 01048 { 01049 long num = 1; 01050 const char *p = string; 01051 01052 if (string == NULL) 01053 return 0; 01054 01055 switch (*p) 01056 { 01057 case '-': 01058 num = -1; 01059 p++; 01060 break; 01061 01062 case '+': 01063 p++; 01064 break; 01065 } 01066 01067 if (dazuko_isdigit(*p)) 01068 { 01069 num *= *p - '0'; 01070 p++; 01071 } 01072 else 01073 { 01074 return 0; 01075 } 01076 01077 while (dazuko_isdigit(*p)) 01078 { 01079 num *= 10; 01080 num += *p - '0'; 01081 p++; 01082 } 01083 01084 return num; 01085 } 01086 01087 static inline int dazuko_strlen(const char *string) 01088 { 01089 const char *p; 01090 01091 if (string == NULL) 01092 return -1; 01093 01094 for (p=string ; *p ; p++) 01095 continue; 01096 01097 return (p - string); 01098 } 01099 01100 static inline const char* dazuko_strchr(const char *haystack, char needle) 01101 { 01102 const char *p; 01103 01104 if (haystack == NULL) 01105 return NULL; 01106 01107 for (p=haystack ; *p ; p++) 01108 { 01109 if (*p == needle) 01110 return p; 01111 } 01112 01113 return NULL; 01114 } 01115 01116 static inline const char* dazuko_strstr(const char *haystack, const char *needle) 01117 { 01118 const char *p1; 01119 const char *p2; 01120 const char *p3; 01121 01122 if (haystack == NULL || needle == NULL) 01123 return NULL; 01124 01125 for (p1=haystack ; *p1 ; p1++) 01126 { 01127 for (p2=needle,p3=p1 ; *p2&&*p3 ; p2++,p3++) 01128 { 01129 if (*p2 != *p3) 01130 break; 01131 } 01132 01133 if (*p2 == 0) 01134 return p1; 01135 } 01136 01137 return NULL; 01138 } 01139 01140 int dazuko_get_value(const char *key, const char *string, char **value) 01141 { 01142 const char *p1; 01143 const char *p2; 01144 int size; 01145 01146 if (value == NULL) 01147 return -1; 01148 01149 *value = NULL; 01150 01151 if (key == NULL || string == NULL) 01152 return -1; 01153 01154 p1 = dazuko_strstr(string, key); 01155 if (p1 == NULL) 01156 return -1; 01157 01158 p1 += dazuko_strlen(key); 01159 01160 for (p2=p1 ; *p2 && *p2!='\n' ; p2++) 01161 continue; 01162 01163 size = (p2 - p1) + 1; 01164 *value = call_xp_malloc(size); 01165 if (*value == NULL) 01166 return -1; 01167 01168 memcpy(*value, p1, size - 1); 01169 (*value)[size - 1] = 0; 01170 01171 return 0; 01172 } 01173 01174 static inline void dazuko_clear_replybuffer(struct dazuko_request *request) 01175 { 01176 dazuko_bzero(request->reply_buffer, request->reply_buffer_size); 01177 request->reply_buffer_size_used = 0; 01178 } 01179 01180 static inline void dazuko_close_replybuffer(struct dazuko_request *request) 01181 { 01182 request->reply_buffer[request->reply_buffer_size_used] = 0; 01183 request->reply_buffer_size_used++; 01184 } 01185 01186 static inline void dazuko_add_keyvalue_to_replybuffer(struct dazuko_request *request, const char *key, void *value, char vtype) 01187 { 01188 01189 #define DAZUKO_VSNPRINT(type, name) dazuko_snprintf(request->reply_buffer + request->reply_buffer_size_used, (request->reply_buffer_size - request->reply_buffer_size_used) - 1, "%s%" #type , key, *((name *)value)) 01190 01191 switch (vtype) 01192 { 01193 case 'd': 01194 DAZUKO_VSNPRINT(d, const int); 01195 break; 01196 01197 case 's': 01198 DAZUKO_VSNPRINT(s, const char *); 01199 break; 01200 01201 case 'l': 01202 DAZUKO_VSNPRINT(lu, const unsigned long); 01203 break; 01204 01205 default: 01206 /* all other types treated as chars */ 01207 DAZUKO_VSNPRINT(c, const char); 01208 break; 01209 } 01210 01211 /* update how much buffer we have used */ 01212 request->reply_buffer_size_used += strlen(request->reply_buffer + request->reply_buffer_size_used); 01213 } 01214 01215 static inline int dazuko_printable(char c) 01216 { 01217 /* hopefully this counts for all operating systems! */ 01218 01219 return ((c >= ' ') && (c <= '~') && (c != '\\')); 01220 } 01221 01222 static inline void dazuko_add_esc_to_replybuffer(struct dazuko_request *request, const char *key, char **filename) 01223 { 01224 int found = 0; 01225 char *p_rq; 01226 const char *limit; 01227 const char *p_fn; 01228 unsigned char c; 01229 01230 /* check for escape characters in filename */ 01231 for (p_fn=*filename ; *p_fn ; p_fn++) 01232 { 01233 if (!dazuko_printable(*p_fn)) 01234 { 01235 found = 1; 01236 break; 01237 } 01238 } 01239 01240 if (found) 01241 { 01242 /* this is expensive, but it will also almost never occur */ 01243 01244 p_rq = request->reply_buffer + request->reply_buffer_size_used; 01245 limit = request->reply_buffer + request->reply_buffer_size - 1; 01246 01247 dazuko_snprintf(p_rq, limit - p_rq, "%s", key); 01248 p_rq += strlen(p_rq); 01249 01250 for (p_fn=*filename ; *p_fn && (p_rq<limit) ; p_fn++) 01251 { 01252 if (dazuko_printable(*p_fn)) 01253 { 01254 *p_rq = *p_fn; 01255 p_rq++; 01256 } 01257 else 01258 { 01259 c = *p_fn & 0xFF; 01260 dazuko_snprintf(p_rq, limit - p_rq, "\\x%02x", c); 01261 p_rq += strlen(p_rq); 01262 } 01263 } 01264 01265 request->reply_buffer_size_used += strlen(request->reply_buffer + request->reply_buffer_size_used); 01266 } 01267 else 01268 { 01269 /* no escape characters found */ 01270 01271 dazuko_add_keyvalue_to_replybuffer(request, key, filename, 's'); 01272 } 01273 } 01274 01275 static int dazuko_set_option(struct daemon_id *did, int opt, void *param, int len) 01276 { 01277 /* The daemon wants to set a configuration 01278 * option in the kernel. */ 01279 01280 struct slot *s; 01281 int error; 01282 01283 /* sanity check */ 01284 if (len < 0 || len > 8192) 01285 return XP_ERROR_PERMISSION; 01286 01287 /* make sure we are already registered 01288 * (or that we don't register twice) */ 01289 01290 /* find our slot */ 01291 s = dazuko_find_slot(did, 1, NULL); 01292 01293 switch (opt) 01294 { 01295 case REGISTER: 01296 call_xp_print("dazuko: dazuko_set_option does not support REGISTER (bug!)\n"); 01297 return XP_ERROR_PERMISSION; 01298 01299 case UNREGISTER: 01300 if (s == NULL) 01301 { 01302 /* We are not registered! */ 01303 01304 return 0; 01305 } 01306 break; 01307 01308 default: 01309 if (s == NULL) 01310 { 01311 error = dazuko_register_daemon(did, "_COMPAT", 7, 1); 01312 if (error) 01313 { 01314 call_xp_print("dazuko: unregistered daemon %d attempted access\n", did->unique); 01315 return XP_ERROR_PERMISSION; 01316 } 01317 01318 s = dazuko_find_slot(did, 1, NULL); 01319 if (s == NULL) 01320 { 01321 call_xp_print("dazuko: unregistered daemon %d attempted access\n", did->unique); 01322 return XP_ERROR_PERMISSION; 01323 } 01324 01325 call_xp_print("dazuko: warning: daemon %d is using a deprecated protocol\n", did->unique); 01326 } 01327 break; 01328 } 01329 01330 /* check option type and take the appropriate action */ 01331 switch (opt) 01332 { 01333 case UNREGISTER: 01334 error = _dazuko_unregister_daemon(did); 01335 if (error) 01336 return error; 01337 break; 01338 01339 case SET_ACCESS_MASK: 01340 memcpy(&access_mask, (char *)param, sizeof(char)); 01341 break; 01342 01343 case ADD_INCLUDE_PATH: 01344 error = dazuko_insert_path_fs(&incl_paths, (char *)param, len); 01345 if (error) 01346 return error; 01347 break; 01348 01349 case ADD_EXCLUDE_PATH: 01350 error = dazuko_insert_path_fs(&excl_paths, (char *)param, len); 01351 if (error) 01352 return error; 01353 break; 01354 01355 case REMOVE_ALL_PATHS: 01356 dazuko_remove_all_paths(); 01357 break; 01358 01359 default: 01360 call_xp_print("dazuko: daemon %d requested unknown set %d (possible bug)\n", did->unique, opt); 01361 break; 01362 } 01363 01364 return 0; 01365 } 01366 01367 static int dazuko_handle_request(struct dazuko_request *request, struct xp_daemon_id *xp_id) 01368 { 01369 char *value1; 01370 char *value2; 01371 int error = 0; 01372 int type; 01373 struct slot *s; 01374 struct daemon_id did; 01375 01376 if (request == NULL || xp_id == NULL) 01377 return -1; 01378 01379 type = request->type[0] + (256 * request->type[1]); 01380 01381 switch (type) 01382 { 01383 case REGISTER: 01384 /* read "\nRM=regmode\nGN=group" */ 01385 /* send "\nID=id" */ 01386 01387 if (request->buffer_size <= 0) 01388 return -1; 01389 01390 if (request->reply_buffer_size <= 0) 01391 return -1; 01392 01393 if (dazuko_get_value("\nGN=", request->buffer, &value1) != 0) 01394 return -1; 01395 01396 if (dazuko_get_value("\nRM=", request->buffer, &value2) != 0) 01397 { 01398 call_xp_free(value1); 01399 return -1; 01400 } 01401 01402 did.xp_id = call_xp_id_copy(xp_id); 01403 did.unique = 0; /* a unique is not yet assigned */ 01404 01405 error = dazuko_register_daemon(&did, value1, dazuko_strlen(value1), dazuko_strchr(value2, 'W') != NULL); 01406 01407 dazuko_clear_replybuffer(request); 01408 dazuko_add_keyvalue_to_replybuffer(request, "\nID=", &(did.unique), 'd'); 01409 dazuko_close_replybuffer(request); 01410 01411 call_xp_free(value1); 01412 call_xp_free(value2); 01413 call_xp_id_free(did.xp_id); 01414 01415 break; 01416 01417 case UNREGISTER: 01418 /* read "\nID=id" */ 01419 01420 if (request->buffer_size <= 0) 01421 return -1; 01422 01423 if (dazuko_get_value("\nID=", request->buffer, &value1) != 0) 01424 return -1; 01425 01426 did.xp_id = call_xp_id_copy(xp_id); 01427 did.unique = dazuko_strtol(value1); 01428 01429 error = dazuko_set_option(&did, UNREGISTER, NULL, 0); 01430 01431 call_xp_free(value1); 01432 call_xp_id_free(did.xp_id); 01433 01434 break; 01435 01436 case SET_ACCESS_MASK: 01437 /* read "\nID=id\nAM=mask" */ 01438 01439 if (request->buffer_size <= 0) 01440 return -1; 01441 01442 if (dazuko_get_value("\nID=", request->buffer, &value1) != 0) 01443 return -1; 01444 01445 if (dazuko_get_value("\nAM=", request->buffer, &value2) != 0) 01446 { 01447 call_xp_free(value1); 01448 return -1; 01449 } 01450 01451 access_mask = (char)dazuko_strtol(value2); 01452 01453 call_xp_free(value1); 01454 call_xp_free(value2); 01455 01456 break; 01457 01458 case ADD_INCLUDE_PATH: 01459 /* read "\nID=id\nPT=path" */ 01460 01461 if (request->buffer_size <= 0) 01462 return -1; 01463 01464 if (dazuko_get_value("\nID=", request->buffer, &value1) != 0) 01465 return -1; 01466 01467 if (dazuko_get_value("\nPT=", request->buffer, &value2) != 0) 01468 { 01469 call_xp_free(value1); 01470 return -1; 01471 } 01472 01473 did.xp_id = call_xp_id_copy(xp_id); 01474 did.unique = dazuko_strtol(value1); 01475 01476 error = dazuko_set_option(&did, ADD_INCLUDE_PATH, value2, dazuko_strlen(value2)); 01477 01478 call_xp_free(value1); 01479 call_xp_free(value2); 01480 call_xp_id_free(did.xp_id); 01481 01482 break; 01483 01484 case ADD_EXCLUDE_PATH: 01485 /* read "\nID=id\nPT=path" */ 01486 01487 if (request->buffer_size <= 0) 01488 return -1; 01489 01490 if (dazuko_get_value("\nID=", request->buffer, &value1) != 0) 01491 return -1; 01492 01493 if (dazuko_get_value("\nPT=", request->buffer, &value2) != 0) 01494 { 01495 call_xp_free(value1); 01496 return -1; 01497 } 01498 01499 did.xp_id = call_xp_id_copy(xp_id); 01500 did.unique = dazuko_strtol(value1); 01501 01502 error = dazuko_set_option(&did, ADD_EXCLUDE_PATH, value2, dazuko_strlen(value2)); 01503 01504 call_xp_free(value1); 01505 call_xp_free(value2); 01506 call_xp_id_free(did.xp_id); 01507 01508 break; 01509 01510 case REMOVE_ALL_PATHS: 01511 /* read "\nID=id" */ 01512 01513 if (request->buffer_size <= 0) 01514 return -1; 01515 01516 if (dazuko_get_value("\nID=", request->buffer, &value1) != 0) 01517 return -1; 01518 01519 did.xp_id = call_xp_id_copy(xp_id); 01520 did.unique = dazuko_strtol(value1); 01521 01522 error = dazuko_set_option(&did, REMOVE_ALL_PATHS, NULL, 0); 01523 01524 call_xp_free(value1); 01525 call_xp_id_free(did.xp_id); 01526 01527 break; 01528 01529 case GET_AN_ACCESS: 01530 /* read "\nID=id" */ 01531 /* send "\nFN=file\nFL=flags\nMD=mode\nUI=uid\nPI=pid" */ 01532 01533 if (request->buffer_size <= 0) 01534 return -1; 01535 01536 if (request->reply_buffer_size <= 0) 01537 return -1; 01538 01539 if (dazuko_get_value("\nID=", request->buffer, &value1) != 0) 01540 return -1; 01541 01542 did.xp_id = call_xp_id_copy(xp_id); 01543 did.unique = dazuko_strtol(value1); 01544 01545 call_xp_free(value1); 01546 01547 /* DOWN? */ 01548 s = dazuko_get_an_access(&did); 01549 01550 if (s == NULL) 01551 { 01552 call_xp_id_free(did.xp_id); 01553 return XP_ERROR_INTERRUPT; 01554 } 01555 /* DOWN */ 01556 01557 /* Slot IS in DAZUKO_WORKING state. Copy all the 01558 * necessary information to userspace structure. */ 01559 01560 dazuko_clear_replybuffer(request); 01561 dazuko_add_keyvalue_to_replybuffer(request, "\nEV=", &(s->event), 'd'); 01562 dazuko_add_esc_to_replybuffer(request, "\nFN=", &(s->filename)); 01563 01564 if (s->event_p.set_uid) 01565 dazuko_add_keyvalue_to_replybuffer(request, "\nUI=", &(s->event_p.uid), 'd'); 01566 01567 if (s->event_p.set_pid) 01568 dazuko_add_keyvalue_to_replybuffer(request, "\nPI=", &(s->event_p.pid), 'd'); 01569 01570 if (s->event_p.set_flags) 01571 dazuko_add_keyvalue_to_replybuffer(request, "\nFL=", &(s->event_p.flags), 'd'); 01572 01573 if (s->event_p.set_mode) 01574 dazuko_add_keyvalue_to_replybuffer(request, "\nMD=", &(s->event_p.mode), 'd'); 01575 01576 if (s->file_p.set_size) 01577 dazuko_add_keyvalue_to_replybuffer(request, "\nFS=", &(s->file_p.size), 'l'); 01578 01579 if (s->file_p.set_uid) 01580 dazuko_add_keyvalue_to_replybuffer(request, "\nFU=", &(s->file_p.uid), 'd'); 01581 01582 if (s->file_p.set_gid) 01583 dazuko_add_keyvalue_to_replybuffer(request, "\nFG=", &(s->file_p.gid), 'd'); 01584 01585 if (s->file_p.set_mode) 01586 dazuko_add_keyvalue_to_replybuffer(request, "\nFM=", &(s->file_p.mode), 'd'); 01587 01588 if (s->file_p.set_device_type) 01589 dazuko_add_keyvalue_to_replybuffer(request, "\nDT=", &(s->file_p.device_type), 'd'); 01590 01591 dazuko_close_replybuffer(request); 01592 01593 /* XXX: What do we do if there is a problem copying back to userspace?! */ 01594 /* dazuko_state_error(s, DAZUKO_WORKING); */ 01595 01596 /* are we in read_only mode? */ 01597 if (!(s->write_mode)) 01598 { 01599 /* the access is immediately (and at the kernel level) 01600 * returned */ 01601 01602 call_xp_up(&(s->mutex)); 01603 /* UP */ 01604 01605 dazuko_return_access(&did, 0, s); 01606 } 01607 else 01608 { 01609 call_xp_up(&(s->mutex)); 01610 /* UP */ 01611 } 01612 01613 call_xp_id_free(did.xp_id); 01614 01615 break; 01616 01617 case RETURN_AN_ACCESS: 01618 /* read "\nID=id\nDN=deny" */ 01619 01620 if (request->buffer_size <= 0) 01621 return -1; 01622 01623 if (dazuko_get_value("\nID=", request->buffer, &value1) != 0) 01624 return -1; 01625 01626 if (dazuko_get_value("\nDN=", request->buffer, &value2) != 0) 01627 { 01628 call_xp_free(value1); 01629 return -1; 01630 } 01631 01632 did.xp_id = call_xp_id_copy(xp_id); 01633 did.unique = dazuko_strtol(value1); 01634 01635 error = dazuko_return_access(&did, dazuko_strtol(value2), NULL); 01636 01637 call_xp_free(value1); 01638 call_xp_free(value2); 01639 call_xp_id_free(did.xp_id); 01640 01641 break; 01642 01643 default: 01644 call_xp_print("dazuko: daemon made unknown request %d (possible bug)\n", type); 01645 01646 break; 01647 } 01648 01649 return error; 01650 } 01651 01652 int dazuko_handle_user_request(struct dazuko_request *user_request, struct xp_daemon_id *xp_id) 01653 { 01654 int error = 0; 01655 struct dazuko_request *request; 01656 struct dazuko_request *temp_request; 01657 01658 if (user_request == NULL || xp_id == NULL) 01659 return XP_ERROR_FAULT; 01660 01661 /* allocate kernel request */ 01662 request = (struct dazuko_request *)call_xp_malloc(sizeof(struct dazuko_request)); 01663 if (request == NULL) 01664 return XP_ERROR_FAULT; 01665 01666 /* use out0 now */ 01667 01668 /* allocate temp kernel request */ 01669 temp_request = (struct dazuko_request *)call_xp_malloc(sizeof(struct dazuko_request)); 01670 if (request == NULL) 01671 { 01672 error = XP_ERROR_FAULT; 01673 goto dazuko_handle_user_request_out0; 01674 } 01675 01676 /* use out1 now */ 01677 01678 /* copy in the request */ 01679 if (call_xp_copyin(user_request, temp_request, sizeof(struct dazuko_request)) != 0) 01680 { 01681 error = XP_ERROR_FAULT; 01682 goto dazuko_handle_user_request_out1; 01683 } 01684 01685 memcpy(request->type, temp_request->type, sizeof(char[2])); 01686 request->buffer_size = temp_request->buffer_size; 01687 01688 /* sanity check */ 01689 if (request->buffer_size < 0 || request->buffer_size > 8192) 01690 { 01691 error = XP_ERROR_FAULT; 01692 goto dazuko_handle_user_request_out1; 01693 } 01694 01695 request->reply_buffer_size = temp_request->reply_buffer_size; 01696 01697 /* sanity check */ 01698 if (request->reply_buffer_size < 0 || request->reply_buffer_size > 8192) 01699 { 01700 error = EPERM; 01701 goto dazuko_handle_user_request_out1; 01702 } 01703 01704 /* allocate buffer */ 01705 request->buffer = (char *)call_xp_malloc(request->buffer_size + 1); 01706 if (request->buffer == NULL) 01707 { 01708 error = XP_ERROR_FAULT; 01709 goto dazuko_handle_user_request_out1; 01710 } 01711 01712 /* use out2 now */ 01713 01714 if (request->reply_buffer_size > 0) 01715 { 01716 /* allocate reply buffer */ 01717 request->reply_buffer = (char *)call_xp_malloc(request->reply_buffer_size + 1); 01718 if (request->reply_buffer == NULL) 01719 { 01720 error = XP_ERROR_FAULT; 01721 goto dazuko_handle_user_request_out2; 01722 } 01723 01724 /* use out3 now */ 01725 01726 request->reply_buffer_size_used = 0; 01727 } 01728 01729 /* copy the buffer from userspace to kernelspace */ 01730 if (call_xp_copyin(temp_request->buffer, request->buffer, request->buffer_size) != 0) 01731 { 01732 error = XP_ERROR_FAULT; 01733 goto dazuko_handle_user_request_out3; 01734 } 01735 01736 request->buffer[request->buffer_size] = 0; 01737 01738 error = dazuko_handle_request(request, xp_id); 01739 01740 if (error == 0 && request->reply_buffer_size > 0) 01741 { 01742 request->reply_buffer[request->reply_buffer_size] = 0; 01743 01744 temp_request->reply_buffer_size_used = request->reply_buffer_size_used; 01745 01746 if (call_xp_copyout(temp_request, user_request, sizeof(struct dazuko_request)) != 0) 01747 { 01748 error = XP_ERROR_FAULT; 01749 goto dazuko_handle_user_request_out3; 01750 } 01751 01752 if (request->reply_buffer_size_used > 0) 01753 { 01754 if (call_xp_copyout(request->reply_buffer, temp_request->reply_buffer, request->reply_buffer_size_used) != 0) 01755 { 01756 error = XP_ERROR_FAULT; 01757 goto dazuko_handle_user_request_out3; 01758 } 01759 } 01760 } 01761 01762 dazuko_handle_user_request_out3: 01763 if (request->reply_buffer_size > 0) 01764 call_xp_free(request->reply_buffer); 01765 dazuko_handle_user_request_out2: 01766 call_xp_free(request->buffer); 01767 dazuko_handle_user_request_out1: 01768 call_xp_free(temp_request); 01769 dazuko_handle_user_request_out0: 01770 call_xp_free(request); 01771 01772 return error; 01773 } 01774 01775 int dazuko_handle_user_request_compat12(void *ptr, int cmd, struct xp_daemon_id *xp_id) 01776 { 01777 struct access_compat12 *user_request12; 01778 struct access_compat12 *temp_request12; 01779 int error = 0; 01780 struct slot *s; 01781 char *k_param; 01782 struct daemon_id did; 01783 int temp_length; 01784 int temp_int; 01785 01786 if (ptr == NULL || xp_id == NULL) 01787 return XP_ERROR_FAULT; 01788 01789 did.xp_id = call_xp_id_copy(xp_id); 01790 did.unique = -1; 01791 01792 switch (cmd) 01793 { 01794 case IOCTL_GET_AN_ACCESS: 01795 /* The daemon is requesting a filename of a file 01796 * to scan. This code will wait until a filename 01797 * is available, or until we should be killed. 01798 * (killing is done if any errors occur as well 01799 * as when the user kills us) */ 01800 01801 user_request12 = (struct access_compat12 *)ptr; 01802 01803 error = call_xp_verify_user_writable(user_request12, sizeof(struct access_compat12)); 01804 if (error) 01805 { 01806 error = XP_ERROR_FAULT; 01807 break; 01808 } 01809 01810 /* DOWN? */ 01811 s = dazuko_get_an_access(&did); 01812 01813 if (s == NULL) 01814 { 01815 error = XP_ERROR_INTERRUPT; 01816 break; 01817 } 01818 01819 /* DOWN */ 01820 01821 /* Slot IS in WORKING state. Copy all the 01822 * necessary information to userspace structure. */ 01823 01824 if (s->filenamelength >= DAZUKO_FILENAME_MAX_LENGTH_COMPAT12) 01825 { 01826 /* filename length overflow :( */ 01827 01828 s->filename[DAZUKO_FILENAME_MAX_LENGTH_COMPAT12 - 1] = 0; 01829 temp_length = DAZUKO_FILENAME_MAX_LENGTH_COMPAT12; 01830 } 01831 else 01832 { 01833 temp_length = s->filenamelength + 1; 01834 } 01835 01836 temp_request12 = (struct access_compat12 *)call_xp_malloc(sizeof(struct access_compat12)); 01837 if (temp_request12 == NULL) 01838 { 01839 error = XP_ERROR_FAULT; 01840 } 01841 else if (call_xp_copyin(user_request12, temp_request12, sizeof(struct access_compat12)) != 0) 01842 { 01843 error = XP_ERROR_FAULT; 01844 } 01845 01846 if (error == 0) 01847 { 01848 temp_request12->event = s->event; 01849 temp_request12->o_flags = s->event_p.flags; 01850 temp_request12->o_mode = s->event_p.mode; 01851 temp_request12->uid = s->event_p.uid; 01852 temp_request12->pid = s->event_p.pid; 01853 memcpy(temp_request12->filename, s->filename, temp_length); 01854 01855 if (call_xp_copyout(temp_request12, user_request12, sizeof(struct access_compat12)) != 0) 01856 { 01857 error = XP_ERROR_FAULT; 01858 } 01859 } 01860 01861 call_xp_up(&(s->mutex)); 01862 /* UP */ 01863 01864 if (error) 01865 { 01866 dazuko_state_error(s, DAZUKO_WORKING); 01867 } 01868 01869 if (temp_request12 != NULL) 01870 { 01871 call_xp_free(temp_request12); 01872 } 01873 01874 break; 01875 01876 case IOCTL_RETURN_ACCESS: 01877 /* The daemon has finished scanning a file 01878 * and has the response to give. The daemon's 01879 * slot should be in the WORKING state. */ 01880 01881 user_request12 = (struct access_compat12 *)ptr; 01882 01883 error = call_xp_verify_user_readable(user_request12, sizeof(struct access_compat12)); 01884 if (error) 01885 { 01886 error = XP_ERROR_FAULT; 01887 break; 01888 } 01889 01890 temp_request12 = (struct access_compat12 *)call_xp_malloc(sizeof(struct access_compat12)); 01891 if (temp_request12 == NULL) 01892 { 01893 error = XP_ERROR_FAULT; 01894 break; 01895 } 01896 01897 if (call_xp_copyin(user_request12, temp_request12, sizeof(struct access_compat12)) != 0) 01898 { 01899 error = XP_ERROR_FAULT; 01900 } 01901 01902 temp_int = temp_request12->deny; 01903 01904 call_xp_free(temp_request12); 01905 01906 error = dazuko_return_access(&did, temp_int, NULL); 01907 break; 01908 01909 case IOCTL_SET_OPTION: 01910 /* The daemon wants to set a configuration 01911 * option in the kernel. */ 01912 01913 error = call_xp_verify_user_readable(ptr, 2*sizeof(int)); 01914 if (error) 01915 { 01916 error = XP_ERROR_FAULT; 01917 break; 01918 } 01919 01920 /* copy option type from userspace */ 01921 if (call_xp_copyin(ptr, &temp_int, sizeof(int)) != 0) 01922 { 01923 error = XP_ERROR_FAULT; 01924 break; 01925 } 01926 01927 ptr = ((char *)ptr + sizeof(int)); 01928 01929 /* copy path length from userspace */ 01930 if (call_xp_copyin(ptr, &temp_length, sizeof(int)) != 0) 01931 { 01932 error = XP_ERROR_FAULT; 01933 break; 01934 } 01935 01936 /* sanity check */ 01937 if (temp_length < 0 || temp_length > 4096) 01938 { 01939 error = XP_ERROR_INVALID; 01940 break; 01941 } 01942 01943 ptr = ((char *)ptr + sizeof(int)); 01944 01945 error = call_xp_verify_user_readable(ptr, temp_length); 01946 if (error) 01947 { 01948 error = XP_ERROR_FAULT; 01949 break; 01950 } 01951 01952 k_param = (char *)call_xp_malloc(temp_length + 1); 01953 if (k_param == NULL) 01954 { 01955 error = XP_ERROR_FAULT; 01956 break; 01957 } 01958 01959 /* We must copy the param from userspace to kernelspace. */ 01960 01961 if (call_xp_copyin(ptr, k_param, temp_length) != 0) 01962 { 01963 call_xp_free(k_param); 01964 error = XP_ERROR_FAULT; 01965 break; 01966 } 01967 01968 k_param[temp_length] = 0; 01969 01970 if (temp_int == REGISTER) 01971 error = dazuko_register_daemon(&did, k_param, temp_length, 1); 01972 else 01973 error = dazuko_set_option(&did, temp_int, k_param, temp_length); 01974 01975 call_xp_free(k_param); 01976 01977 break; 01978 01979 default: 01980 call_xp_print("dazuko: daemon requested unknown device_ioctl %d (possible bug)\n", cmd); 01981 01982 break; 01983 } 01984 01985 call_xp_id_free(did.xp_id); 01986 01987 return error; 01988 } 01989 01990 static struct slot * dazuko_get_and_hold_ready_slot(struct slot_list *sl) 01991 { 01992 /* This is a simple search to find a 01993 * slot whose state is DAZUKO_READY. This means 01994 * it is able to accept work. If a slot 01995 * is found, the slot.mutex is held so 01996 * it can be filled with work by the caller. 01997 * It is the responsibility of the caller 01998 * to RELEASE THE MUTEX. */ 01999 02000 int i; 02001 struct slot *s; 02002 02003 for (i=0 ; i<NUM_SLOTS ; i++) 02004 { 02005 s = &(sl->slots[i]); 02006 /* DOWN? */ 02007 if (dazuko_change_slot_state(s, DAZUKO_READY, DAZUKO_WAITING, 0)) 02008 { 02009 /* DOWN */ 02010 return s; 02011 } 02012 } 02013 02014 /* we didn't find a slot that is ready for work */ 02015 02016 return NULL; 02017 } 02018 02019 static int get_ready_slot_condition(void *param) 02020 { 02021 return ((((struct get_ready_slot_condition_param *)param)->slot = dazuko_get_and_hold_ready_slot(((struct get_ready_slot_condition_param *)param)->slotlist)) != NULL 02022 || call_xp_atomic_read(&active) == 0 02023 || call_xp_atomic_read(&(((struct get_ready_slot_condition_param *)param)->slotlist->use_count)) == 0); 02024 } 02025 02026 static int dazuko_run_daemon_on_slotlist(int event, char *filename, int filenamelength, struct event_properties *event_p, struct file_properties *file_p, int prev_response, struct slot_list *sl) 02027 { 02028 /* This is the main function called by the kernel 02029 * to work with a daemon. */ 02030 02031 int rc; 02032 int unique; 02033 struct slot *s; 02034 struct get_ready_slot_condition_param cond_p1; 02035 struct two_slot_state_not_condition_param cond_p2; 02036 02037 begin: 02038 /* we initialize the slot value because 02039 * we cannot guarentee that it will be 02040 * assigned a new value BEFORE !active 02041 * is checked */ 02042 s = NULL; 02043 02044 /* wait for a slot to become ready */ 02045 cond_p1.slotlist = sl; 02046 cond_p1.slot = s; 02047 if (call_xp_wait_until_condition(&wait_kernel_waiting_for_free_slot, get_ready_slot_condition, &cond_p1, 0) != 0) 02048 { 02049 /* The kernel process was killed while 02050 * waiting for a slot to become ready. 02051 * This is fine. */ 02052 02053 DPRINT(("dazuko: kernel process %d killed while waiting for free slot\n", event_p->pid)); 02054 02055 return -1; /* user interrupted */ 02056 } 02057 02058 /* Make sure we have a slot. We may have 02059 * gotten past the last wait because we 02060 * are no longer active. */ 02061 02062 s = cond_p1.slot; 02063 02064 if (s == NULL) 02065 { 02066 /* We were no longer active. We don't 02067 * need to initiate a daemon. This also 02068 * means we never acquired the lock. */ 02069 02070 return 0; /* allow access */ 02071 } 02072 02073 /* DOWN */ 02074 02075 /* the slot is already locked at this point */ 02076 02077 /* grab the daemon's unique */ 02078 unique = s->did.unique; 02079 02080 /* At this point we have a locked slot. It IS 02081 * sitting in the DAZUKO_WAITING state, waiting for 02082 * us to give it some work. */ 02083 02084 /* set up the slot to do work */ 02085 s->filename = filename; 02086 s->event = event; 02087 s->response = prev_response; 02088 s->filenamelength = filenamelength; 02089 02090 if (event_p == NULL) 02091 dazuko_bzero(&(s->event_p), sizeof(struct event_properties)); 02092 else 02093 memcpy(&(s->event_p), event_p, sizeof(struct event_properties)); 02094 02095 if (file_p == NULL) 02096 dazuko_bzero(&(s->file_p), sizeof(struct file_properties)); 02097 else 02098 memcpy(&(s->file_p), file_p, sizeof(struct file_properties)); 02099 02100 /* we are done modifying the slot */ 02101 call_xp_up(&(s->mutex)); 02102 /* UP */ 02103 02104 /* wake up any daemons waiting for work */ 02105 call_xp_notify(&wait_daemon_waiting_for_work); 02106 02107 /* wait until the daemon is finished with the slot */ 02108 cond_p2.slot1 = s; 02109 cond_p2.state1 = DAZUKO_WAITING; 02110 cond_p2.slot2 = s; 02111 cond_p2.state2 = DAZUKO_WORKING; 02112 if (call_xp_wait_until_condition(&wait_kernel_waiting_while_daemon_works, two_slot_state_not_condition, &cond_p2, 0) != 0) 02113 { 02114 /* The kernel process was killed while 02115 * waiting for a daemon to process the file. 02116 * This is fine. */ 02117 02118 DPRINT(("dazuko: kernel process %d killed while waiting for daemon response\n", event_p->pid)); 02119 02120 /* change the slot's state to let the 02121 * daemon know we are not interested 02122 * in a response */ 02123 dazuko_change_slot_state(s, DAZUKO_FREE, DAZUKO_FREE, 1); 02124 02125 return -1; /* user interrupted */ 02126 } 02127 02128 /* we are working with the slot, so 02129 * we need to lock it */ 02130 /* DOWN */ 02131 if (call_xp_down(&(s->mutex)) != 0) 02132 { 02133 return -1; /* user interrupted */ 02134 } 02135 02136 /* make sure this is the right daemon */ 02137 if (s->did.unique != unique) 02138 { 02139 /* This is a different daemon than 02140 * the one we assigned work to. 02141 * We need to scan again. */ 02142 call_xp_up(&(s->mutex)); 02143 /* UP */ 02144 goto begin; 02145 } 02146 02147 /* The slot should now be in the DAZUKO_DONE state. */ 02148 if (!__dazuko_change_slot_state(s, DAZUKO_DONE, DAZUKO_FREE)) 02149 { 02150 /* The daemon was killed while scanning. 02151 * We need to scan again. */ 02152 02153 call_xp_up(&(s->mutex)); 02154 /* UP */ 02155 goto begin; 02156 } 02157 02158 /* grab the response */ 02159 rc = s->response; 02160 02161 call_xp_up(&(s->mutex)); 02162 /* UP */ 02163 02164 /* CONGRATULATIONS! You successfully completed a full state cycle! */ 02165 02166 return rc; 02167 } 02168 02169 static int dazuko_run_daemon(int event, char *filename, int filenamelength, struct event_properties *event_p, struct file_properties *file_p) 02170 { 02171 struct slot_list *sl; 02172 int i; 02173 int rc = 0; 02174 int error; 02175 02176 if (event_p != NULL) 02177 { 02178 if (event_p->thrown) 02179 return 0; 02180 event_p->thrown = 1; 02181 } 02182 02183 for (i=0 ; i<NUM_SLOT_LISTS ; i++) 02184 { 02185 /* DOWN */ 02186 /* if we are interrupted, we report error */ 02187 if (call_xp_down(&(slot_lists[i].mutex)) != 0) 02188 return XP_ERROR_INTERRUPT; 02189 02190 sl = slot_lists[i].slot_list; 02191 02192 call_xp_up(&(slot_lists[i].mutex)); 02193 /* UP */ 02194 02195 if (sl != NULL) 02196 { 02197 error = dazuko_run_daemon_on_slotlist(event, filename, filenamelength, event_p, file_p, rc, sl); 02198 02199 if (error < 0) 02200 { 02201 /* most likely user interrupt */ 02202 rc = error; 02203 break; 02204 } 02205 else if (error > 0) 02206 { 02207 /* this daemon wants access blocked */ 02208 rc = 1; 02209 } 02210 } 02211 } 02212 02213 return rc; 02214 } 02215 02216 inline int dazuko_is_our_daemon(struct xp_daemon_id *xp_id) 02217 { 02218 /* Check if the current process is one 02219 * of the daemons. */ 02220 02221 struct daemon_id did; 02222 int ret; 02223 02224 did.xp_id = call_xp_id_copy(xp_id); 02225 did.unique = -1; 02226 02227 ret = (dazuko_find_slot(&did, 1, NULL) != NULL); 02228 02229 call_xp_id_free(did.xp_id); 02230 02231 return ret; 02232 } 02233 02234 static int dazuko_is_selected(char *filename, int len) 02235 { 02236 /* Check if the given filename (with path) is 02237 * under our include directories but not under 02238 * the exclude directories. */ 02239 02240 struct path *path; 02241 02242 /* If we are interrupted here, we will report that 02243 * this file is not selected. This will make the 02244 * kernel allow normal access. Is this dangerous? */ 02245 /* LOCK */ 02246 call_xp_read_lock(&lock_lists); 02247 02248 /* check if filename is under our include paths */ 02249 for (path=incl_paths ; path ; path=path->next) 02250 { 02251 /* the include item must be at least as long as the given filename */ 02252 if (path->len <= len) 02253 { 02254 /* the include item should match the beginning of the given filename */ 02255 if (memcmp(path->path, filename, path->len) == 0) 02256 break; 02257 } 02258 } 02259 02260 /* If we didn't find a path, it isn't in our 02261 * include directories. It can't be one of 02262 * the selected files to scan. */ 02263 if (!path) 02264 { 02265 call_xp_read_unlock(&lock_lists); 02266 /* UNLOCK */ 02267 return 0; 02268 } 02269 02270 /* check if filename is under our exclude paths */ 02271 for (path=excl_paths ; path ; path=path->next) 02272 { 02273 /* the exclude item must be at least as long as the given filename */ 02274 if (path->len <= len) 02275 { 02276 /* the exclude item should match the beginning of the given filename */ 02277 if (memcmp(path->path,filename,path->len) == 0) 02278 break; 02279 } 02280 } 02281 02282 call_xp_read_unlock(&lock_lists); 02283 /* UNLOCK */ 02284 02285 /* If we got a path, then we are supposed 02286 * to exclude this file for scanning. */ 02287 if (path) 02288 return 0; 02289 02290 /* if we made it this far, it is a selected file to scan */ 02291 02292 return 1; 02293 } 02294 02295 static int dazuko_add_hash(struct xp_file *file, char *filename, int len) 02296 { 02297 /* Add the given file and filename to the linked list 02298 * of files to scan once they are closed. */ 02299 02300 struct hash *h; 02301 02302 /* create a new struct hash structure making room for name also */ 02303 h = (struct hash *)call_xp_malloc(sizeof(struct hash) + len); 02304 if (!h) 02305 return XP_ERROR_FAULT; 02306 02307 /* fill in structure items */ 02308 02309 call_xp_copy_file(&(h->file), file); 02310 h->dirty = 0; 02311 h->namelen = len; 02312 memcpy(h->name, filename, len); 02313 h->name[len] = 0; 02314 02315 /* add the new struct hash item to the head of the 02316 * struct hash linked list */ 02317 02318 /* LOCK */ 02319 call_xp_write_lock(&lock_hash); 02320 h->next = hash; 02321 hash = h; 02322 call_xp_write_unlock(&lock_hash); 02323 /* UNLOCK */ 02324 return 0; 02325 } 02326 02327 /* Code based on code from: Swade 12/08/02: Move dirty to end of list */ 02328 static void dazuko_mark_hash_dirty(struct xp_file *file) 02329 { 02330 struct hash *h = NULL; 02331 struct hash *entry = NULL; 02332 struct hash *prev = NULL; 02333 struct hash *prev_entry = NULL; 02334 02335 /* LOCK */ 02336 call_xp_write_lock(&lock_hash); 02337 02338 for (h=hash ; h ; h=h->next) 02339 { 02340 /* not found if hit first dirty entry */ 02341 if (h->dirty) 02342 { 02343 entry = NULL; 02344 break; 02345 } 02346 02347 if (call_xp_compare_file(&(h->file), file) == 0) 02348 { 02349 /* we found the entry */ 02350 02351 prev_entry = prev; 02352 entry = h; 02353 break; 02354 } 02355 02356 prev = h; 02357 } 02358 02359 if (entry) 02360 { 02361 if (!entry->dirty) 02362 { 02363 /* mark as dirty */ 02364 entry->dirty = 1; 02365 02366 /* If we already are last entry or next 02367 * entry dirty, we don't need to move */ 02368 02369 if (entry->next) 02370 { 02371 if (!entry->next->dirty) 02372 { 02373 for (h=entry->next ; h ; h=h->next) 02374 { 02375 if (h->dirty) 02376 break; 02377 02378 prev = h; 02379 } 02380 02381 /* remove from current position */ 02382 if (prev_entry) 02383 prev_entry->next = entry->next; 02384 else 02385 hash = entry->next; 02386 02387 if (prev == NULL) 02388 { 02389 /* insert as first item */ 02390 entry->next = hash; 02391 hash = entry; 02392 } 02393 else if (h) 02394 { 02395 /* insert before h (after prev) */ 02396 entry->next = prev->next; 02397 prev->next = entry; 02398 } 02399 else 02400 { 02401 /* insert as last item (after prev) */ 02402 entry->next = NULL; 02403 prev->next = entry; 02404 } 02405 } 02406 } 02407 } 02408 } 02409 02410 call_xp_write_unlock(&lock_hash); 02411 /* UNLOCK */ 02412 02413 } 02414 02415 static struct hash *dazuko_get_hash(struct xp_file *file) 02416 { 02417 /* Find the given file within our list 02418 * and then remove it from the list and 02419 * return it. */ 02420 02421 struct hash *prev; 02422 struct hash *cur; 02423 02424 /* LOCK */ 02425 call_xp_write_lock(&lock_hash); 02426 02427 prev = NULL; 02428 cur = hash; 02429 while (cur) 02430 { 02431 if (call_xp_compare_file(&(cur->file), file) == 0) 02432 { 02433 /* we found the entry */ 02434 02435 /* remove the item from the list */ 02436 if (!prev) 02437 hash = cur->next; 02438 else 02439 prev->next = cur->next; 02440 break; 02441 } 02442 02443 prev = cur; 02444 cur = cur->next; 02445 } 02446 02447 call_xp_write_unlock(&lock_hash); 02448 /* UNLOCK */ 02449 02450 return cur; 02451 } 02452 02453 inline int dazuko_get_filename_length(char *filename) 02454 { 02455 int len; 02456 02457 for (len=0 ; filename[len] ; len++); 02458 02459 return len; 02460 } 02461 02462 static int dazuko_should_scan(struct dazuko_file_struct *kfs) 02463 { 02464 /* Check if we are supposed to scan this file. 02465 * This checks for all the correct file types, 02466 * permissions, and if it is within the desired 02467 * paths to scan. */ 02468 02469 int result = 0; 02470 02471 /* check if we already know if we scan this file */ 02472 switch (kfs->should_scan) 02473 { 02474 /* case 0 means that we do not know yet. This is a little 02475 * confusing, because 0 represents uninitialized. However, 02476 * the should_scan variable is used in this function ONLY 02477 * so this optimization shouldn't cause any problems. */ 02478 02479 case 1: 02480 /* we already know it should be scanned */ 02481 return 1; 02482 02483 case 2: 02484 /* we already know it should not be scanned */ 02485 return 0; 02486 } 02487 02488 /* make necessary platform-dependent checks */ 02489 if (call_xp_file_struct_check(kfs) == 0) 02490 { 02491 if (dazuko_is_selected(kfs->filename, kfs->filename_length)) 02492 { 02493 /* If we made it this far, we are supposed 02494 * to scan this file. We mark it so that 02495 * any further immediate inquiries don't have 02496 * to do all this work all over again. */ 02497 02498 /* yes, should be scanned */ 02499 kfs->should_scan = 1; 02500 02501 result = 1; 02502 } 02503 else 02504 { 02505 /* We will still mark it so that any further 02506 * immediate inquiries don't have to do all 02507 * this work all over again. */ 02508 02509 /* no, should not be scanned */ 02510 kfs->should_scan = 2; 02511 } 02512 } 02513 02514 call_xp_file_struct_check_cleanup(kfs); 02515 02516 return result; 02517 } 02518 02519 inline int dazuko_sys_check(unsigned long event, int daemon_is_allowed, struct xp_daemon_id *xp_id) 02520 { 02521 /* is this event in our mask? */ 02522 switch (event) 02523 { 02524 case DAZUKO_ON_OPEN: 02525 /* this is a special case because the on_close information needs 02526 * to be saved during the on_open event */ 02527 02528 if ((SCAN_ON_OPEN || SCAN_ON_CLOSE || SCAN_ON_CLOSE_MODIFIED) == 0) 02529 return -1; 02530 break; 02531 02532 case DAZUKO_ON_CLOSE: 02533 /* will need to scan if ON_CLOSE_MODIFIED is in the mask too */ 02534 02535 if ((SCAN_ON_CLOSE || SCAN_ON_CLOSE_MODIFIED) == 0) 02536 return -1; 02537 break; 02538 02539 default: 02540 if ((access_mask & event) == 0) 02541 return -1; 02542 break; 02543 } 02544 02545 /* do we have any daemons? */ 02546 if (call_xp_atomic_read(&active) <= 0) 02547 return -1; 02548 02549 /* should daemons be allowed this event without a scan? */ 02550 if (daemon_is_allowed) 02551 { 02552 if (dazuko_is_our_daemon(xp_id)) 02553 { 02554 /* this is one of our daemons, so we will report as 02555 * as if this event was not in the mask */ 02556 02557 return -1; 02558 } 02559 } 02560 02561 return 0; 02562 } 02563 02564 inline int dazuko_sys_pre(unsigned long event, struct dazuko_file_struct *kfs, struct event_properties *event_p) 02565 { 02566 /* return codes: 02567 * >0 -> access should be blocked 02568 * <0 -> access should be blocked (because user interrupted) 02569 * 0 -> access is allowed 02570 */ 02571 02572 int error = 0; 02573 02574 switch (event) 02575 { 02576 case DAZUKO_ON_OPEN: 02577 /* special case, because this pre may be called 02578 * in order to record ON_CLOSE events (in post) */ 02579 02580 if (!SCAN_ON_OPEN) 02581 return 0; 02582 break; 02583 02584 case DAZUKO_ON_CLOSE: 02585 /* handled in post */ 02586 02587 return 0; 02588 02589 case DAZUKO_ON_CLOSE_MODIFIED: 02590 /* (this is really sys_write) always permitted */ 02591 02592 return 0; 02593 02594 default: 02595 break; 02596 } 02597 02598 if (kfs == NULL) 02599 { 02600 /* if the file structure wasn't provided, then 02601 * we will allow the access */ 02602 02603 return 0; 02604 } 02605 02606 /* make sure we should scan this file */ 02607 if (dazuko_should_scan(kfs)) 02608 { 02609 error = dazuko_run_daemon(event, kfs->filename, kfs->filename_length, event_p, &(kfs->file_p)); 02610 } 02611 02612 if (error > 0) 02613 { 02614 /* access will be blocked */ 02615 02616 /* dazuko_sys_post should NOT be called! */ 02617 02618 return XP_ERROR_PERMISSION; 02619 } 02620 else if (error < 0) 02621 { 02622 /* user interrupted */ 02623 02624 /* dazuko_sys_post should NOT be called! */ 02625 02626 return XP_ERROR_INTERRUPT; 02627 } 02628 02629 /* access allowed */ 02630 02631 return 0; 02632 } 02633 02634 inline int dazuko_sys_post(unsigned long event, struct dazuko_file_struct *kfs, struct xp_file *file, struct event_properties *event_p) 02635 { 02636 struct hash *h = NULL; 02637 02638 switch (event) 02639 { 02640 case DAZUKO_ON_OPEN: /* kfs,file required */ 02641 /* if the file was opened and we are interested 02642 * in scanning on close, add this file to our struct hash list */ 02643 02644 if ((call_xp_atomic_read(&active) > 0) && file != NULL && kfs != NULL) 02645 { 02646 if (SCAN_ON_OPEN || SCAN_ON_CLOSE || SCAN_ON_CLOSE_MODIFIED) 02647 { 02648 /* make sure we should scan this file */ 02649 if (dazuko_should_scan(kfs)) 02650 { 02651 /* hash is added if we were given an xp_file */ 02652 if (file != NULL) 02653 dazuko_add_hash(file, kfs->filename, kfs->filename_length); 02654 02655 dazuko_run_daemon(event, kfs->filename, kfs->filename_length, event_p, &(kfs->file_p)); 02656 } 02657 } 02658 } 02659 break; 02660 02661 case DAZUKO_ON_CLOSE: /* file,o_flags,o_mode,pid,uid required */ 02662 if (file != NULL) 02663 { 02664 /* find hash entry and remove it from list */ 02665 h = dazuko_get_hash(file); 02666 02667 /* if we found the file in our list and the file was 02668 * successfully closed, we need to scan it */ 02669 if (h != NULL) 02670 { 02671 /* determine if we are scanning on close or close_modified */ 02672 02673 /* note that close_modified has priority over just close */ 02674 02675 if (SCAN_ON_CLOSE_MODIFIED && h->dirty) 02676 dazuko_run_daemon(DAZUKO_ON_CLOSE_MODIFIED, h->name, h->namelen, event_p, NULL); 02677 else if (SCAN_ON_CLOSE) 02678 dazuko_run_daemon(DAZUKO_ON_CLOSE, h->name, h->namelen, event_p, NULL); 02679 02680 /* clean up the struct hash structure */ 02681 call_xp_free(h); 02682 } 02683 } 02684 else 02685 { 02686 if (SCAN_ON_CLOSE) 02687 { 02688 if (dazuko_should_scan(kfs)) 02689 { 02690 dazuko_run_daemon(DAZUKO_ON_CLOSE, kfs->filename, kfs->filename_length, event_p, &(kfs->file_p)); 02691 } 02692 } 02693 } 02694 break; 02695 02696 case DAZUKO_ON_CLOSE_MODIFIED: /* file required */ 02697 if (file != NULL) 02698 { 02699 /* if we actually wrote something and we found the 02700 * file in our list, set it as dirty */ 02701 02702 /* Swade 4/24/02: Move to end of clean list */ 02703 dazuko_mark_hash_dirty(file); 02704 } 02705 break; 02706 02707 default: 02708 break; 02709 } 02710 02711 return 0; 02712 } 02713 02714 inline int dazuko_init(void) 02715 { 02716 int i; 02717 int error; 02718 02719 call_xp_init_mutex(&mutex_unique_count); 02720 02721 call_xp_init_rwlock(&lock_hash); 02722 call_xp_init_rwlock(&lock_lists); 02723 02724 call_xp_init_queue(&wait_kernel_waiting_for_free_slot); 02725 call_xp_init_queue(&wait_daemon_waiting_for_work); 02726 call_xp_init_queue(&wait_kernel_waiting_while_daemon_works); 02727 call_xp_init_queue(&wait_daemon_waiting_for_free); 02728 02729 dazuko_bzero(&slot_lists, sizeof(slot_lists)); 02730 02731 for (i=0 ; i<NUM_SLOT_LISTS ; i++) 02732 call_xp_init_mutex(&(slot_lists[i].mutex)); 02733 02734 call_xp_atomic_set(&active, 0); 02735 02736 error = call_xp_sys_hook(); 02737 02738 if (error == 0) 02739 call_xp_print("dazuko: loaded, version=%s\n", VERSION); 02740 02741 return error; 02742 } 02743 02744 inline int dazuko_exit(void) 02745 { 02746 int error; 02747 int i; 02748 int j; 02749 02750 i = call_xp_atomic_read(&active); 02751 02752 if (i != 0) 02753 { 02754 call_xp_print("dazuko: warning: trying to remove Dazuko with %d process%s still registered\n", i, i==1 ? "" : "es"); 02755 return -1; 02756 } 02757 02758 dazuko_remove_all_paths(); 02759 dazuko_remove_all_hash(); 02760 02761 error = call_xp_sys_unhook(); 02762 02763 if (error == 0) 02764 { 02765 call_xp_destroy_mutex(&mutex_unique_count); 02766 02767 call_xp_destroy_rwlock(&lock_hash); 02768 call_xp_destroy_rwlock(&lock_lists); 02769 02770 call_xp_destroy_queue(&wait_kernel_waiting_for_free_slot); 02771 call_xp_destroy_queue(&wait_daemon_waiting_for_work); 02772 call_xp_destroy_queue(&wait_kernel_waiting_while_daemon_works); 02773 call_xp_destroy_queue(&wait_daemon_waiting_for_free); 02774 02775 for (i=0 ; i<NUM_SLOT_LISTS ; i++) 02776 { 02777 if (slot_lists[i].slot_list != NULL) 02778 { 02779 if (call_xp_atomic_read(&(slot_lists[i].slot_list->use_count)) != 0) 02780 call_xp_print("dazuko: slot_list count was not 0 (possible bug)\n"); 02781 02782 for (j=0 ; j<NUM_SLOTS ; j++) 02783 { 02784 call_xp_destroy_mutex(&(slot_lists[i].slot_list->slots[j].mutex)); 02785 } 02786 02787 call_xp_free(slot_lists[i].slot_list); 02788 slot_lists[i].slot_list = NULL; 02789 } 02790 02791 call_xp_destroy_mutex(&(slot_lists[i].mutex)); 02792 } 02793 02794 call_xp_print("dazuko: unloaded, version=%s\n", VERSION); 02795 } 02796 02797 return error; 02798 }

Generated on Tue Aug 31 10:05:23 2004 for RSBAC by doxygen 1.3.8