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

Generated on Fri Jun 17 09:45:19 2005 for RSBAC by  doxygen 1.4.2