dazuko_core.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, 2005, 2006 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 #include "dazuko_core.h"
00037 #include "dazuko_version.h"
00038 
00039 /* inline code */
00040 #include "dazuko_call.h"
00041 
00042 /* binary version stamp */
00043 const char      *DAZUKO_VERSION_STAMP = "\nDazukoVersion=" DAZUKO_VERSION_MAJOR "." DAZUKO_VERSION_MINOR "." DAZUKO_VERSION_REVISION "." DAZUKO_VERSION_RELEASE "\n";
00044 
00045 /* version string for display */
00046 const char      *VERSION_STRING = DAZUKO_VERSION_MAJOR "." DAZUKO_VERSION_MINOR "." DAZUKO_VERSION_REVISION
00047 #ifdef DAZUKO_PRERELEASE
00048 "-pre" DAZUKO_VERSION_RELEASE
00049 #endif
00050 ;
00051 
00052 /* technical version string */
00053 const char      *VERSION_NUMBER = DAZUKO_VERSION_MAJOR "." DAZUKO_VERSION_MINOR "." DAZUKO_VERSION_REVISION "." DAZUKO_VERSION_RELEASE;
00054 
00055 #define NUM_SLOT_LISTS  5
00056 #define NUM_SLOTS       25
00057 #define NUM_EVENTS      7
00058 
00059 #define AMC_UNSET       255
00060 
00061 /* slot states */
00062 #define DAZUKO_FREE     0       /* the daemon is not ready */
00063 #define DAZUKO_READY    1       /* a daemon waits for something to do */
00064 #define DAZUKO_WAITING  2       /* a request is waiting to be served */
00065 #define DAZUKO_WORKING  3       /* daemon is currently in action */
00066 #define DAZUKO_DONE     4       /* daemon response is available */
00067 #define DAZUKO_BROKEN   5       /* invalid state (interrupt from ready,waiting) */
00068 
00069 #define TRUSTED_APPLICATION_SUPPORT
00070 
00071 struct path
00072 {
00073         /* A node in a linked list of paths. Used
00074          * for the include and exclude lists. */
00075 
00076         struct path     *next;
00077         int             len;
00078         char            *path;
00079 };
00080 
00081 struct daemon_id
00082 {
00083         int                     unique;
00084         struct xp_daemon_id     *xp_id;
00085 };
00086 
00087 #ifdef TRUSTED_APPLICATION_SUPPORT
00088 struct trusted_container
00089 {
00090         struct xp_daemon_id             *xp_id;
00091         char                            *token;
00092         int                             token_length;
00093         int                             trust_children;
00094         struct trusted_container        *next;
00095 };
00096 #endif
00097 
00098 struct slot_list;
00099 
00100 struct slot
00101 {
00102         /* A representation of a daemon. It holds
00103          * all information about the daemon, the
00104          * file that is scanned, and the state of
00105          * the scanning process. */
00106 
00107         int                     id;             
00108         struct daemon_id        did;            /* identifier for our daemon */
00109         int                     write_mode;
00110         int                     state;
00111         int                     response;
00112         int                     event;
00113         int                     filenamelength; /* not including terminator */
00114         char                    *filename;
00115         struct event_properties event_p;
00116         struct file_properties  file_p;
00117         struct xp_mutex         mutex;
00118         struct slot_list        *slot_list;
00119         struct xp_queue         wait_daemon_waiting_until_this_slot_not_READY;
00120         struct xp_queue         wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING;
00121         struct xp_queue         wait_daemon_waiting_until_this_slot_not_DONE;
00122 };
00123 
00124 struct slot_list
00125 {
00126         struct xp_atomic                use_count;
00127         struct slot                     slots[NUM_SLOTS];
00128         struct path                     *incl_paths;
00129         struct path                     *excl_paths;
00130         char                            *reg_name;
00131         struct xp_rwlock                lock_lists;
00132         char                            access_mask;
00133 #ifdef TRUSTED_APPLICATION_SUPPORT
00134         struct xp_rwlock                lock_trusted_list;
00135         struct trusted_container        *trusted_list;
00136         char                            set_trusted_list;
00137 #endif
00138         struct xp_queue                 wait_kernel_waiting_for_any_READY_slot_or_zero_use_count;
00139 };
00140 
00141 struct slot_list_container
00142 {
00143         struct slot_list        *slot_list;
00144         struct xp_mutex         mutex;
00145 };
00146 
00147 struct one_slot_state_not_condition_param
00148 {
00149         struct slot     *slot;
00150         int             state;
00151 };
00152 
00153 struct two_slot_state_not_condition_param
00154 {
00155         struct slot     *slot1;
00156         int             state1;
00157         struct slot     *slot2;
00158         int             state2;
00159 };
00160 
00161 struct get_ready_slot_condition_param
00162 {
00163         struct slot             *slot;
00164         struct slot_list        *slotlist;
00165 };
00166 
00167 static int                              unique_count = 1;
00168 static struct slot_list_container       slot_lists[NUM_SLOT_LISTS];
00169 static struct xp_atomic                 active;
00170 static struct xp_atomic                 groupcount;
00171 static struct xp_mutex                  mutex_unique_count;
00172 static unsigned char                    access_mask_cache[NUM_EVENTS][NUM_SLOT_LISTS];
00173 static struct xp_mutex                  mutex_amc;
00174 
00175 
00176 int dazuko_vsnprintf(char *str, size_t size, const char *format, va_list ap)
00177 {
00178         char            *target;
00179         const char      *end;
00180         int             overflow = 0;
00181         char            number_buffer[32]; /* 32 should be enough to hold any number, right? */
00182         const char      *s;
00183 
00184         if (str == NULL || size < 1 || format == NULL)
00185                 return -1;
00186 
00187         target = str;
00188         end = (target + size) - 1;
00189 
00190 #define DAZUKO_VSNPRINTF_PRINTSTRING \
00191         for ( ; *s ; s++) \
00192         { \
00193                 if (target == end) \
00194                 { \
00195                         overflow = 1; \
00196                         goto dazuko_vsnprintf_out; \
00197                 } \
00198                 *target = *s; \
00199                 target++; \
00200         }
00201 
00202         for ( ; *format ; format++)
00203         {
00204                 if (target == end)
00205                 {
00206                         overflow = 1;
00207                         goto dazuko_vsnprintf_out;
00208                 }
00209 
00210                 if (*format == '%')
00211                 {
00212                         format++;
00213 
00214                         switch (*format)
00215                         {
00216                                 case 's': /* %s */
00217                                         s = va_arg(ap, char *);
00218                                         if (s == NULL)
00219                                                 s = "(null)";
00220                                         DAZUKO_VSNPRINTF_PRINTSTRING
00221                                         break;
00222 
00223                                 case 'd': /* %d */
00224                                         sprintf(number_buffer, "%d", va_arg(ap, int));
00225                                         s = number_buffer;
00226                                         DAZUKO_VSNPRINTF_PRINTSTRING
00227                                         break;
00228 
00229                                 case 'p': /* %p */
00230                                         sprintf(number_buffer, "%p", va_arg(ap, void *));
00231                                         s = number_buffer;
00232                                         DAZUKO_VSNPRINTF_PRINTSTRING
00233                                         break;
00234 
00235                                 case 'c': /* %c */
00236                                         *target = va_arg(ap, int);
00237                                         target++;
00238                                         break;
00239 
00240                                 case 'l': /* %lu */
00241                                         format++;
00242                                         if (*format != 'u')
00243                                         {
00244                                                 /* print error message */
00245                                                 goto dazuko_vsnprintf_out;
00246                                         }
00247                                         sprintf(number_buffer, "%lu", va_arg(ap, unsigned long));
00248                                         s = number_buffer;
00249                                         DAZUKO_VSNPRINTF_PRINTSTRING
00250                                         break;
00251 
00252                                 case '0': /* %02x */
00253                                         format++;
00254                                         if (*format != '2')
00255                                         {
00256                                                 /* print error message */
00257                                                 goto dazuko_vsnprintf_out;
00258                                         }
00259                                         format++;
00260                                         if (*format != 'x')
00261                                         {
00262                                                 /* print error message */
00263                                                 goto dazuko_vsnprintf_out;
00264                                         }
00265                                         sprintf(number_buffer, "%02x", va_arg(ap, int));
00266                                         s = number_buffer;
00267                                         DAZUKO_VSNPRINTF_PRINTSTRING
00268                                         break;
00269 
00270                                 default:
00271                                         /* print error message */
00272                                         goto dazuko_vsnprintf_out;
00273                         }
00274                 }
00275                 else
00276                 {
00277                         *target = *format;
00278                         target++;
00279                 }
00280         }
00281 
00282 dazuko_vsnprintf_out:
00283 
00284         *target = 0;
00285 
00286         /* We are returning what we've written. If there was an
00287          * overflow, the returned value will match "size" rather
00288          * than being less than "size"
00289          */
00290 
00291         return ((target - str) + overflow);
00292 }
00293 
00294 int dazuko_snprintf(char *str, size_t size, const char *format, ...)
00295 {
00296         va_list ap;
00297         int     ret;
00298 
00299         va_start(ap, format);
00300         ret = dazuko_vsnprintf(str, size, format, ap);
00301         va_end(ap);
00302 
00303         return ret;
00304 }
00305 
00306 inline void dazuko_bzero(void *p, int len)
00307 {
00308         /* "zero out" len bytes starting with p */
00309 
00310         char    *ptr = (char *)p;
00311 
00312         while (len--)
00313                 *ptr++ = 0;
00314 }
00315 
00316 static inline int dazuko_event2index(unsigned long event)
00317 {
00318         switch (event)
00319         {
00320                 case DAZUKO_ON_OPEN:
00321                         return 0;
00322                 case DAZUKO_ON_CLOSE:
00323                         return 1;
00324                 case DAZUKO_ON_EXEC:
00325                         return 2;
00326                 case DAZUKO_ON_CLOSE_MODIFIED:
00327                         return 3;
00328                 case DAZUKO_ON_UNLINK:
00329                         return 4;
00330                 case DAZUKO_ON_RMDIR:
00331                         return 5;
00332                 case DAZUKO_TRUST_REQUEST:
00333                         return 6;
00334         }
00335 
00336         return -1;
00337 }
00338 
00339 static inline unsigned long dazuko_index2event(int index)
00340 {
00341         switch (index)
00342         {
00343                 case 0:
00344                         return DAZUKO_ON_OPEN;
00345                 case 1:
00346                         return DAZUKO_ON_CLOSE;
00347                 case 2:
00348                         return DAZUKO_ON_EXEC;
00349                 case 3:
00350                         return DAZUKO_ON_CLOSE_MODIFIED;
00351                 case 4:
00352                         return DAZUKO_ON_UNLINK;
00353                 case 5:
00354                         return DAZUKO_ON_RMDIR;
00355                 case 6:
00356                         return DAZUKO_TRUST_REQUEST;
00357         }
00358 
00359         return 0;
00360 }
00361 
00362 static void dazuko_setup_amc_cache(void)
00363 {
00364         int                     i;
00365         int                     j;
00366         struct slot_list        *sl;
00367         unsigned long           event;
00368         int                     index;
00369 
00370 /* DOWN */
00371         call_xp_down(&mutex_amc);
00372 
00373         memset(&access_mask_cache, AMC_UNSET, sizeof(access_mask_cache));
00374 
00375         for (i=0 ; i<NUM_EVENTS ; i++)
00376         {
00377                 event = dazuko_index2event(i);
00378                 if (event == 0)
00379                         continue;
00380 
00381                 index = 0;
00382 
00383                 for (j=0 ; j<NUM_SLOT_LISTS ; j++)
00384                 {
00385 /* DOWN */
00386                         call_xp_down(&(slot_lists[j].mutex));
00387 
00388                         sl = slot_lists[j].slot_list;
00389 
00390                         call_xp_up(&(slot_lists[j].mutex));
00391 /* UP */
00392 
00393                         if (sl == NULL)
00394                                 continue;
00395 
00396                         switch (event)
00397                         {
00398                                 case DAZUKO_ON_CLOSE:
00399                                         /* this is a special case since ON_CLOSE_MODIFIED
00400                                          * also triggers ON_CLOSE events */
00401 
00402                                         if (((DAZUKO_ON_CLOSE | DAZUKO_ON_CLOSE_MODIFIED) & (sl->access_mask)) == 0)
00403                                                 continue;
00404                                         break;
00405                                 default:
00406                                         if ((event & (sl->access_mask)) == 0)
00407                                                 continue;
00408                                         break;
00409                         }
00410 
00411                         /* if we made it this far, then the
00412                          * event is in the access mask */
00413 
00414                         access_mask_cache[i][index] = j;
00415                         index++;
00416                 }
00417         }
00418 
00419         call_xp_up(&mutex_amc);
00420 /* UP */
00421 }
00422 
00423 
00424 static inline int dazuko_get_new_unique(void)
00425 {
00426         int     unique;
00427 
00428 /* DOWN */
00429         call_xp_down(&mutex_unique_count);
00430 
00431         unique = unique_count;
00432         unique_count++;
00433 
00434         call_xp_up(&mutex_unique_count);
00435 /* UP */
00436 
00437         return unique;
00438 }
00439 
00440 static inline int dazuko_slot_state(struct slot *s)
00441 {
00442         int state;
00443 
00444 /* DOWN */
00445         call_xp_down(&(s->mutex));
00446 
00447         state = s->state;
00448 
00449         call_xp_up(&(s->mutex));
00450 /* UP */
00451 
00452         return state;
00453 }
00454 
00455 static int one_slot_state_not_condition(void *param)
00456 {
00457         return (dazuko_slot_state(((struct one_slot_state_not_condition_param *)param)->slot)
00458                 != ((struct one_slot_state_not_condition_param *)param)->state);
00459 }
00460 
00461 static int two_slot_state_not_condition(void *param)
00462 {
00463         return (dazuko_slot_state(((struct two_slot_state_not_condition_param *)param)->slot1)
00464                 != ((struct two_slot_state_not_condition_param *)param)->state1
00465                 && dazuko_slot_state(((struct two_slot_state_not_condition_param *)param)->slot2)
00466                 != ((struct two_slot_state_not_condition_param *)param)->state2);
00467 }
00468 
00469 static inline int __dazuko_change_slot_state(struct slot *s, int from_state, int to_state)
00470 {
00471         /* Make a predicted state transition. We fail if it
00472          * is an unpredicted change. We can ALWAYS go to the
00473          * to_state if it is the same as from_state. Not SMP safe! */
00474 
00475         if (to_state != from_state)
00476         {
00477                 /* make sure this is a predicted transition and there
00478                  * is a daemon on this slot (unique != 0)*/
00479                 if (s->state != from_state || s->did.unique == 0)
00480                         return 0;
00481         }
00482 
00483         s->state = to_state;
00484 
00485         /* handle appropriate wake_up's for basic
00486          * state changes */
00487 
00488         return 1;
00489 }
00490 
00491 static int dazuko_change_slot_state(struct slot *s, int from_state, int to_state, int release)
00492 {
00493         /* SMP safe version of __dazuko_change_slot_state().
00494          * This should only be used if we haven't
00495          * already aquired slot.mutex. Use this function
00496          * with CAUTION, since the mutex may or may not
00497          * be released depending on the return value AND
00498          * on the value of the "release" argument. */
00499 
00500         int     success;
00501 
00502 /* DOWN */
00503         call_xp_down(&(s->mutex));
00504 
00505         success = __dazuko_change_slot_state(s, from_state, to_state);
00506 
00507         /* the mutex is released if the state change was
00508          * unpredicted or if the called wants it released */
00509         if (!success || release)
00510                 call_xp_up(&(s->mutex));
00511 
00512 /* UP? */
00513 
00514         return success;
00515 }
00516 
00517 static struct slot * _dazuko_find_slot(struct daemon_id *did, int release, struct slot_list *sl)
00518 {
00519         /* Find the first slot with the same given
00520          * pid number. SMP safe. Use this function
00521          * with CAUTION, since the mutex may or may not
00522          * be released depending on the return value AND
00523          * on the value of the "release" argument. */
00524 
00525         int     i;
00526         struct slot     *s = NULL;
00527 
00528         if (sl == NULL)
00529         {
00530                 call_xp_print("dazuko: invalid slot_list given (bug!)\n");
00531                 return NULL;
00532         }
00533 
00534         for (i=0 ; i<NUM_SLOTS ; i++)
00535         {
00536                 s = &(sl->slots[i]);
00537 /* DOWN */
00538                 call_xp_down(&(s->mutex));
00539 
00540                 if (did == NULL)
00541                 {
00542                         /* we are looking for an empty slot */
00543                         if (s->did.unique == 0 && s->did.xp_id == NULL)
00544                         {
00545                                 /* we release the mutex only if the
00546                                 * called wanted us to */
00547                                 if (release)
00548                                         call_xp_up(&(s->mutex));
00549 
00550 /* UP? */
00551 
00552                                 return s;
00553                         }
00554                 }
00555                 else if (s->did.unique == 0 && s->did.xp_id == NULL)
00556                 {
00557                         /* this slot is emtpy, so it can't match */
00558 
00559                         /* do nothing */
00560                 }
00561                 /* xp_id's must match! */
00562                 else if (call_xp_id_compare(s->did.xp_id, did->xp_id, 0) == DAZUKO_SAME)
00563                 {
00564                         /* unique's must also match (unless unique is negative,
00565                          * in which case we will trust xp_id) */
00566                         if (did->unique < 0 || (s->did.unique == did->unique))
00567                         {
00568                                 /* we release the mutex only if the
00569                                  * called wanted us to */
00570                                 if (release)
00571                                         call_xp_up(&(s->mutex));
00572 
00573 /* UP? */
00574 
00575                                 return s;
00576                         }
00577                 }
00578 
00579                 call_xp_up(&(s->mutex));
00580 /* UP */
00581         }
00582 
00583         return NULL;
00584 }
00585 
00586 static struct slot * dazuko_find_slot_and_slotlist(struct daemon_id *did, int release, struct slot_list *slist, struct slot_list **sl_result)
00587 {
00588         struct slot             *s;
00589         int                     i;
00590         struct slot_list        *sl;
00591 
00592         if (slist == NULL)
00593         {
00594                 for (i=0 ; i<NUM_SLOT_LISTS ; i++)
00595                 {
00596 /* DOWN */
00597                         call_xp_down(&(slot_lists[i].mutex));
00598 
00599                         sl = slot_lists[i].slot_list;
00600 
00601                         call_xp_up(&(slot_lists[i].mutex));
00602 /* UP */
00603 
00604                         if (sl != NULL)
00605                         {
00606                                 s = _dazuko_find_slot(did, release, sl);
00607                                 if (s != NULL)
00608                                 {
00609                                         /* set the current slot_list */
00610                                         if (sl_result != NULL)
00611                                                 *sl_result = sl;
00612 
00613                                         return s;
00614                                 }
00615                         }
00616                 }
00617         }
00618         else
00619         {
00620                 return _dazuko_find_slot(did, release, slist);
00621         }
00622 
00623         return NULL;
00624 }
00625 
00626 static inline struct slot * dazuko_find_slot(struct daemon_id *did, int release, struct slot_list *slist)
00627 {
00628         return dazuko_find_slot_and_slotlist(did, release, slist, NULL);
00629 }
00630 
00631 static int dazuko_insert_path_fs(struct path **list, struct xp_rwlock *lock_lists, char *fs_path, int fs_len)
00632 {
00633         /* Create a new struct path structure and insert it
00634          * into the linked list given (list argument).
00635          * The fs_len argument is to help speed things
00636          * up so we don't have to calculate the length
00637          * of fs_path. */
00638 
00639         struct path     *newitem;
00640         struct path     *tmp;
00641 
00642         if (list == NULL || lock_lists == NULL || fs_path == NULL || fs_len < 1)
00643                 return XP_ERROR_INVALID;
00644 
00645         /* we want only absolute paths */
00646         if (!call_xp_is_absolute_path(fs_path))
00647                 return XP_ERROR_INVALID;
00648 
00649         /* create a new struct path structure making room for path also */
00650         newitem = (struct path *)call_xp_malloc(sizeof(struct path));
00651         if (newitem == NULL)
00652                 return XP_ERROR_FAULT;
00653 
00654         newitem->path = (char *)call_xp_malloc(fs_len + 1);
00655         if (newitem->path == NULL)
00656         {
00657                 call_xp_free(newitem);
00658                 return XP_ERROR_FAULT;
00659         }
00660 
00661         /* fs_path is already in kernelspace */
00662         memcpy(newitem->path, fs_path, fs_len);
00663 
00664         newitem->path[fs_len] = 0;
00665 
00666         while (newitem->path[fs_len-1] == 0)
00667         {
00668                 fs_len--;
00669                 if (fs_len == 0)
00670                         break;
00671         }
00672 
00673         if (fs_len < 1)
00674         {
00675                 call_xp_free(newitem->path);
00676                 call_xp_free(newitem);
00677                 return XP_ERROR_INVALID;
00678         }
00679 
00680         newitem->len = fs_len;
00681 
00682         /* check if this path already exists in the list */
00683         for (tmp=*list ; tmp ; tmp=tmp->next)
00684         {
00685                 if (newitem->len == tmp->len)
00686                 {
00687                         if (memcmp(newitem->path, tmp->path, tmp->len) == 0)
00688                         {
00689                                 /* we already have this path */
00690 
00691                                 call_xp_free(newitem->path);
00692                                 call_xp_free(newitem);
00693 
00694                                 return 0;
00695                         }
00696                 }
00697         }
00698 
00699         DPRINT(("dazuko: adding path %s\n", newitem->path));
00700 
00701         /* add struct path to head of linked list */
00702 /* LOCK */
00703         call_xp_write_lock(lock_lists);
00704         newitem->next = *list;
00705         *list = newitem;
00706         call_xp_write_unlock(lock_lists);
00707 /* UNLOCK */
00708 
00709         return 0;
00710 }
00711 
00712 static void dazuko_remove_all_paths(struct slot_list *slist)
00713 {
00714         /* Empty both include and exclude struct path
00715          * linked lists. */
00716 
00717         struct path     *tmp;
00718 
00719         if (slist == NULL)
00720                 return;
00721 
00722 /* LOCK */
00723         call_xp_write_lock(&(slist->lock_lists));
00724 
00725         /* empty include paths list */
00726         while (slist->incl_paths)
00727         {
00728                 tmp = slist->incl_paths;
00729                 slist->incl_paths = slist->incl_paths->next;
00730 
00731                 DPRINT(("dazuko: removing incl %s\n", tmp->path));
00732 
00733                 if (tmp->path != NULL)
00734                         call_xp_free(tmp->path);
00735                 call_xp_free(tmp);
00736         }
00737 
00738         /* empty exclude paths list */
00739         while (slist->excl_paths)
00740         {
00741                 tmp = slist->excl_paths;
00742                 slist->excl_paths = slist->excl_paths->next;
00743 
00744                 DPRINT(("dazuko: removing excl %s\n", tmp->path));
00745 
00746                 if (tmp->path != NULL)
00747                         call_xp_free(tmp->path);
00748                 call_xp_free(tmp);
00749         }
00750 
00751         call_xp_write_unlock(&(slist->lock_lists));
00752 /* UNLOCK */
00753 }
00754 
00755 static int _dazuko_unregister_daemon(struct daemon_id *did)
00756 {
00757         /* We unregister the daemon by finding the
00758          * slot with the same slot->pid as the the
00759          * current process id, the daemon. */
00760 
00761         struct slot             *s;
00762         struct slot_list        *sl;
00763 
00764         DPRINT(("dazuko: dazuko_unregister_daemon() [%d]\n", did->unique));
00765 
00766         /* find our slot and hold the mutex
00767          * if we find it */
00768 /* DOWN? */
00769         s = dazuko_find_slot_and_slotlist(did, 0, NULL, &sl);
00770 
00771         if (s == NULL)
00772         {
00773                 /* this daemon was not registered */
00774                 return 0;
00775         }
00776 
00777 /* DOWN */
00778 
00779         /* clearing the unique and pid makes the slot available */
00780         s->did.unique = 0;
00781         call_xp_id_free(s->did.xp_id);
00782         s->did.xp_id = NULL;
00783 
00784         /* reset slot state */
00785         __dazuko_change_slot_state(s, DAZUKO_FREE, DAZUKO_FREE);
00786 
00787         call_xp_up(&(s->mutex));
00788 /* UP */
00789 
00790         call_xp_atomic_dec(&(sl->use_count));
00791 
00792         /* Remove all the include and exclude paths
00793          * if there are no more daemons in this group */
00794 
00795         if (call_xp_atomic_read(&(sl->use_count)) == 0)
00796         {
00797                 sl->access_mask = 0;
00798                 dazuko_setup_amc_cache();
00799                 dazuko_remove_all_paths(sl);
00800 
00801                 /* this was the last daemon in the group */
00802                 call_xp_atomic_dec(&groupcount);
00803         }
00804 
00805         /* active should always be positive here, but
00806          * let's check just to be sure. ;) */
00807         if (call_xp_atomic_read(&active) > 0)
00808         {
00809                 /* active and the kernel usage counter
00810                  * should always reflect how many daemons
00811                  * are active */
00812 
00813                 call_xp_atomic_dec(&active);
00814         }
00815         else
00816         {
00817                 call_xp_print("dazuko: active count error (possible bug)\n");
00818         }
00819 
00820         /* slot->state has changed to FREE, notifiy appropriate queues */
00821         /* we need to notify all slot queues because unique could be -1,
00822          * which means that it is possible that this process does not
00823          * really belong to this slot */
00824         call_xp_notify(&(s->wait_daemon_waiting_until_this_slot_not_DONE));
00825         call_xp_notify(&(s->wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING));
00826         call_xp_notify(&(s->wait_daemon_waiting_until_this_slot_not_READY));
00827 
00828         /* slotlist->use_count has been decreased, notify appropriate queue */
00829         call_xp_notify(&(sl->wait_kernel_waiting_for_any_READY_slot_or_zero_use_count));
00830 
00831         return 0;
00832 }
00833 
00834 int dazuko_unregister_daemon(struct xp_daemon_id *xp_id)
00835 {
00836         struct daemon_id        did;
00837         int                     ret;
00838 
00839         if (xp_id == NULL)
00840                 return 0;
00841 
00842         did.unique = -1;
00843         did.xp_id = call_xp_id_copy(xp_id);
00844 
00845         ret = _dazuko_unregister_daemon(&did);
00846 
00847         call_xp_id_free(did.xp_id);
00848 
00849         return ret;
00850 }
00851 
00852 static inline struct slot_list* find_slot_list_from_groupname(const char *group_name)
00853 {
00854         int                     i;
00855         struct slot_list        *sl;
00856         const char              *p1;
00857         const char              *p2;
00858 
00859         for (i=0 ; i<NUM_SLOT_LISTS ; i++)
00860         {
00861 /* DOWN */
00862                 call_xp_down(&(slot_lists[i].mutex));
00863 
00864                 sl = slot_lists[i].slot_list;
00865 
00866                 call_xp_up(&(slot_lists[i].mutex));
00867 /* UP */
00868 
00869                 if (sl != NULL)
00870                 {
00871                         p1 = group_name;
00872                         p2 = sl->reg_name;
00873 
00874                         while (*p1 == *p2)
00875                         {
00876                                 if (*p1 == 0)
00877                                         break;
00878 
00879                                 p1++;
00880                                 p2++;
00881                         }
00882 
00883                         if (*p1 == *p2)
00884                                 return sl;
00885                 }
00886         }
00887 
00888         return NULL;
00889 }
00890 
00891 static int dazuko_register_daemon(struct daemon_id *did, const char *reg_name, int string_length, int write_mode)
00892 {
00893         const char              *p1;
00894         char                    *p2;
00895         struct slot             *s;
00896         struct slot_list        *sl;
00897         int                     i;
00898 
00899         DPRINT(("dazuko: dazuko_register_daemon() [%d]\n", did->unique));
00900 
00901         if (did == NULL || reg_name == NULL)
00902                 return XP_ERROR_PERMISSION;
00903 
00904         s = dazuko_find_slot(did, 1, NULL);
00905 
00906         if (s != NULL)
00907         {
00908                 /* We are already registered! */
00909 
00910                 call_xp_print("dazuko: daemon %d already assigned to slot[%d]\n", did->unique, s->id);
00911 
00912                 return XP_ERROR_PERMISSION;
00913         }
00914 
00915         /* Find the slot_list with the matching name. */
00916 
00917         sl = find_slot_list_from_groupname(reg_name);
00918 
00919         if (sl == NULL)
00920         {
00921                 /* There is no slot_list with this name. We
00922                  * need to make one. */
00923 
00924                 sl = (struct slot_list *)call_xp_malloc(sizeof(struct slot_list));
00925                 if (sl == NULL)
00926                         return XP_ERROR_FAULT;
00927 
00928                 dazuko_bzero(sl, sizeof(struct slot_list));
00929 
00930                 sl->reg_name = call_xp_malloc(string_length + 1);
00931                 if (sl->reg_name == NULL)
00932                 {
00933                         call_xp_free(sl);
00934                         return XP_ERROR_FAULT;
00935                 }
00936                 dazuko_bzero(sl->reg_name, string_length + 1);
00937 
00938                 call_xp_atomic_set(&(sl->use_count), 0);
00939                 call_xp_init_rwlock(&(sl->lock_lists));
00940 #ifdef TRUSTED_APPLICATION_SUPPORT
00941                 call_xp_init_rwlock(&(sl->lock_trusted_list));
00942 #endif
00943                 call_xp_init_queue(&(sl->wait_kernel_waiting_for_any_READY_slot_or_zero_use_count));
00944 
00945                 p1 = reg_name;
00946                 p2 = sl->reg_name;
00947 
00948                 while (*p1)
00949                 {
00950                         *p2 = *p1;
00951 
00952                         p1++;
00953                         p2++;
00954                 }
00955                 *p2 = 0;
00956 
00957                 /* give each slot a unique id and assign slot_list */
00958                 for (i=0 ; i<NUM_SLOTS ; i++)
00959                 {
00960                         sl->slots[i].id = i;
00961                         sl->slots[i].slot_list = sl;
00962                         call_xp_init_mutex(&(sl->slots[i].mutex));
00963                         call_xp_init_queue(&(sl->slots[i].wait_daemon_waiting_until_this_slot_not_READY));
00964                         call_xp_init_queue(&(sl->slots[i].wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING));
00965                         call_xp_init_queue(&(sl->slots[i].wait_daemon_waiting_until_this_slot_not_DONE));
00966                 }
00967 
00968                 /* we need to find an empty slot */
00969                 for (i=0 ; i<NUM_SLOT_LISTS ; i++)
00970                 {
00971 /* DOWN */
00972                         call_xp_down(&(slot_lists[i].mutex));
00973 
00974                         if (slot_lists[i].slot_list == NULL)
00975                         {
00976                                 slot_lists[i].slot_list = sl;
00977 
00978                                 call_xp_up(&(slot_lists[i].mutex));
00979 /* UP */
00980                                 break;
00981                         }
00982 
00983                         call_xp_up(&(slot_lists[i].mutex));
00984 /* UP */
00985                 }
00986 
00987                 if (i == NUM_SLOT_LISTS)
00988                 {
00989                         /* no empty slot :( */
00990 
00991                         call_xp_free(sl->reg_name);
00992                         call_xp_free(sl);
00993 
00994                         return XP_ERROR_BUSY;
00995                 }
00996         }
00997 
00998         /* find an available slot and hold the mutex
00999          * if we find one */
01000 /* DOWN? */
01001         s = dazuko_find_slot(NULL, 0, sl);
01002 
01003         if (s == NULL)
01004                 return XP_ERROR_BUSY;
01005 
01006 /* DOWN */
01007 
01008         /* We have found a slot, so increment the active
01009          * variable and the kernel module use counter.
01010          * The module counter will always reflect the
01011          * number of daemons. */
01012 
01013         call_xp_atomic_inc(&active);
01014 
01015         /* get new unique id for this process */
01016         did->unique = dazuko_get_new_unique();
01017 
01018         s->did.unique = did->unique;
01019         s->did.xp_id = call_xp_id_copy(did->xp_id);
01020         s->write_mode = write_mode;
01021 
01022         call_xp_atomic_inc(&(sl->use_count));
01023 
01024         if (call_xp_atomic_read(&(sl->use_count)) == 1)
01025         {
01026                 /* this is the first daemon in the group */
01027                 call_xp_atomic_inc(&groupcount);
01028         }
01029 
01030         /* the daemon is registered, but not yet
01031          * ready to receive files */
01032         __dazuko_change_slot_state(s, DAZUKO_FREE, DAZUKO_FREE);
01033 
01034         DPRINT(("dazuko: slot[%d] assigned to daemon %d\n", s->id, s->did.unique));
01035 
01036         call_xp_up(&(s->mutex));
01037 /* UP */
01038 
01039         /* although there was a state change, we don't need to notify any queues
01040          * because a new slot is first interesting when it hits the READY state */
01041 
01042         return 0;
01043 }
01044 
01045 static struct slot* dazuko_get_an_access(struct daemon_id *did)
01046 {
01047         /* The daemon is requesting a filename of a file
01048          * to scan. This code will wait until a filename
01049          * is available, or until we should be killed.
01050          * (killing is done if any errors occur as well
01051          * as when the user kills us) */
01052 
01053         /* If a slot is returned, it will be already locked! */
01054 
01055         int                                     i;
01056         struct slot                                     *s;
01057         struct one_slot_state_not_condition_param       cond_p;
01058 
01059 tryagain:
01060         /* find our slot */
01061         s = dazuko_find_slot(did, 1, NULL);
01062 
01063         if (s == NULL)
01064         {
01065                 i = dazuko_register_daemon(did, "_COMPAT", 7, 1);
01066                 if (i != 0)
01067                 {
01068                         call_xp_print("dazuko: unregistered daemon %d attempted to get access\n", did->unique);
01069                         return NULL;
01070                 }
01071 
01072                 s = dazuko_find_slot(did, 1, NULL);
01073                 if (s == NULL)
01074                 {
01075                         call_xp_print("dazuko: unregistered daemon %d attempted to get access\n", did->unique);
01076                         return NULL;
01077                 }
01078 
01079                 call_xp_print("dazuko: warning: daemon %d is using a deprecated protocol\n", did->unique);
01080         }
01081 
01082         /* the daemon is now ready to receive a file */
01083 
01084         if (!dazuko_change_slot_state(s, DAZUKO_FREE, DAZUKO_READY, 1))
01085         {
01086                 /* force change (because daemon is ready) */
01087                 dazuko_change_slot_state(s, DAZUKO_READY, DAZUKO_READY, 1);
01088 
01089                 /* unexpected state change, notify other kernel queue */
01090                 call_xp_notify(&(s->wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING));
01091         }
01092 
01093         /* slot->state has changed to READY, notify appropriate queue */
01094         call_xp_notify(&(s->slot_list->wait_kernel_waiting_for_any_READY_slot_or_zero_use_count));
01095 
01096         cond_p.slot = s;
01097         cond_p.state = DAZUKO_READY;
01098         if (call_xp_wait_until_condition(&(s->wait_daemon_waiting_until_this_slot_not_READY), one_slot_state_not_condition, &cond_p, 1) != 0)
01099         {
01100                 /* The user has issued an interrupt.
01101                  * Return an error. The daemon should
01102                  * unregister itself. */
01103 
01104                 DPRINT(("dazuko: daemon %d killed while waiting for work\n", did->unique));
01105 
01106                 if (dazuko_change_slot_state(s, DAZUKO_READY, DAZUKO_BROKEN, 1) || dazuko_change_slot_state(s, DAZUKO_WAITING, DAZUKO_BROKEN, 1))
01107                 {
01108                         /* slot->state has changed to BROKEN, notifiy appropriate queue */
01109                         call_xp_notify(&(s->wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING));
01110                 }
01111 
01112                 return NULL;
01113         }
01114 
01115         /* slot SHOULD now be in DAZUKO_WAITING state */
01116 
01117         /* we will be working with the slot, so
01118          * we need to lock it */
01119 
01120 /* DOWN? */
01121         if (!dazuko_change_slot_state(s, DAZUKO_WAITING, DAZUKO_WORKING, 0))
01122         {
01123                 /* State transition error. Try again., */
01124 
01125                 goto tryagain;
01126         }
01127 
01128 /* DOWN */
01129 
01130         /* Slot IS in DAZUKO_WORKING state. Copy all the
01131          * necessary information to userspace structure. */
01132 
01133         /* IMPORTANT: slot is still locked! */
01134 
01135         return s;  /* access is available */
01136 }
01137 
01138 static int dazuko_initialize_cache(struct daemon_id *did, unsigned long ttl)
01139 {
01140         /* find our slot */
01141         if (dazuko_find_slot(did, 1, NULL) == NULL)
01142         {
01143                 /* this daemon is not registered! */
01144 
01145                 return -1;
01146         }
01147 
01148         return call_xp_init_cache(ttl);
01149 }
01150 
01151 static int dazuko_return_access(struct daemon_id *did, int response, struct slot *s)
01152 {
01153         /* The daemon has finished scanning a file
01154          * and has the response to give. The daemon's
01155          * slot should be in the DAZUKO_WORKING state. */
01156 
01157         struct one_slot_state_not_condition_param       cond_p;
01158 
01159         if (s == NULL)
01160                 return -1;
01161 
01162         /* we will be writing into the slot, so we
01163          * need to lock it */
01164 
01165 /* DOWN? */
01166         if (!dazuko_change_slot_state(s, DAZUKO_WORKING, DAZUKO_DONE, 0))
01167         {
01168                 /* The slot is in the wrong state. We will
01169                  * assume the kernel has cancelled the file
01170                  * access. */
01171 
01172                 DPRINT(("dazuko: response from daemon %d on slot[%d] not needed\n", did->unique, s->id));
01173 
01174                 return 0;
01175         }
01176 
01177 /* DOWN */
01178 
01179         s->response = response;
01180 
01181         call_xp_up(&(s->mutex));
01182 /* UP */
01183 
01184         /* slot->state has changed to DONE, notifiy appropriate queues */
01185         call_xp_notify(&(s->wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING));
01186 
01187         cond_p.slot = s;
01188         cond_p.state = DAZUKO_DONE;
01189         if (call_xp_wait_until_condition(&(s->wait_daemon_waiting_until_this_slot_not_DONE), one_slot_state_not_condition, &cond_p, 1) != 0)
01190         {
01191                 /* The user has issued an interrupt.
01192                  * Return an error. The daemon should
01193                  * unregister itself. */
01194 
01195                 DPRINT(("dazuko: daemon %d killed while waiting for response acknowledgement\n", did->unique));
01196 
01197                 return XP_ERROR_INTERRUPT;
01198         }
01199 
01200         return 0;
01201 }
01202 
01203 static inline int dazuko_isdigit(const char c)
01204 {
01205         return (c >= '0' && c <= '9');
01206 }
01207 
01208 static inline unsigned long dazuko_strtoul(const char *string)
01209 {
01210         unsigned long   num = 1;
01211         const char      *p = string;
01212 
01213         if (string == NULL)
01214                 return 0;
01215 
01216         if (dazuko_isdigit(*p))
01217         {
01218                 num *= *p - '0';
01219                 p++;
01220         }
01221         else
01222         {
01223                 return 0;
01224         }
01225 
01226         while (dazuko_isdigit(*p))
01227         {
01228                 num *= 10;
01229                 num += *p - '0';
01230                 p++;
01231         }
01232 
01233         return num;
01234 }
01235 
01236 static inline long dazuko_strtol(const char *string)
01237 {
01238         const char      *p = string;
01239 
01240         if (string == NULL)
01241                 return 0;
01242 
01243         switch (*p)
01244         {
01245                 case '-':
01246                         p++;
01247                         return (-1 * ((long)(dazuko_strtoul(p))));
01248 
01249                 case '+':
01250                         p++;
01251                         break;
01252         }
01253 
01254         return (long)dazuko_strtoul(p);
01255 }
01256 
01257 static inline int dazuko_strlen(const char *string)
01258 {
01259         const char      *p;
01260 
01261         if (string == NULL)
01262                 return -1;
01263 
01264         for (p=string ; *p ; p++)
01265                 continue;
01266 
01267         return (p - string);
01268 }
01269 
01270 static inline const char* dazuko_strchr(const char *haystack, char needle)
01271 {
01272         const char      *p;
01273 
01274         if (haystack == NULL)
01275                 return NULL;
01276 
01277         for (p=haystack ; *p ; p++)
01278         {
01279                 if (*p == needle)
01280                         return p;
01281         }
01282 
01283         return NULL;
01284 }
01285 
01286 static inline const char* dazuko_strstr(const char *haystack, const char *needle)
01287 {
01288         const char      *p1;
01289         const char      *p2;
01290         const char      *p3;
01291 
01292         if (haystack == NULL || needle == NULL)
01293                 return NULL;
01294 
01295         for (p1=haystack ; *p1 ; p1++)
01296         {
01297                 for (p2=needle,p3=p1 ; *p2&&*p3 ; p2++,p3++)
01298                 {
01299                         if (*p2 != *p3)
01300                                 break;
01301                 }
01302 
01303                 if (*p2 == 0)
01304                         return p1;
01305         }
01306 
01307         return NULL;
01308 }
01309 
01310 int dazuko_get_value(const char *key, const char *string, char **value)
01311 {
01312         const char      *p1;
01313         const char      *p2;
01314         int             size;
01315 
01316         if (value == NULL)
01317                 return -1;
01318 
01319         *value = NULL;
01320 
01321         if (key == NULL || string == NULL)
01322                 return -1;
01323 
01324         p1 = dazuko_strstr(string, key);
01325         if (p1 == NULL)
01326                 return -1;
01327 
01328         p1 += dazuko_strlen(key);
01329 
01330         for (p2=p1 ; *p2 && *p2!='\n' ; p2++)
01331                 continue;
01332 
01333         size = (p2 - p1) + 1;
01334         *value = call_xp_malloc(size);
01335         if (*value == NULL)
01336                 return -1;
01337 
01338         memcpy(*value, p1, size - 1);
01339         (*value)[size - 1] = 0;
01340 
01341         return 0;
01342 }
01343 
01344 static inline void dazuko_clear_replybuffer(struct dazuko_request *request)
01345 {
01346         dazuko_bzero(request->reply_buffer, request->reply_buffer_size);
01347         request->reply_buffer_size_used = 0;
01348 }
01349 
01350 static inline void dazuko_close_replybuffer(struct dazuko_request *request)
01351 {
01352         request->reply_buffer[request->reply_buffer_size_used] = 0;
01353         request->reply_buffer_size_used++;
01354 }
01355 
01356 static void dazuko_add_keyvalue_to_replybuffer(struct dazuko_request *request, const char *key, void *value, char vtype)
01357 {
01358 
01359 #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))
01360 
01361         switch (vtype)
01362         {
01363                 case 'd':
01364                         DAZUKO_VSNPRINT(d, const int);
01365                         break;
01366 
01367                 case 's':
01368                         DAZUKO_VSNPRINT(s, const char *);
01369                         break;
01370 
01371                 case 'l':
01372                         DAZUKO_VSNPRINT(lu, const unsigned long);
01373                         break;
01374 
01375                 default:
01376                         /* all other types treated as chars */
01377                         DAZUKO_VSNPRINT(c, const char);
01378                         break;
01379         }
01380 
01381         /* update how much buffer we have used */
01382         request->reply_buffer_size_used += dazuko_strlen(request->reply_buffer + request->reply_buffer_size_used);
01383 }
01384 
01385 static inline int dazuko_printable(char c)
01386 {
01387         /* hopefully this counts for all operating systems! */
01388 
01389         return ((c >= ' ') && (c <= '~') && (c != '\\'));
01390 }
01391 
01392 static inline void dazuko_add_esc_to_replybuffer(struct dazuko_request *request, const char *key, char **filename)
01393 {
01394         int             found = 0;
01395         char            *p_rq;
01396         const char      *limit;
01397         const char      *p_fn;
01398         unsigned char   c;
01399 
01400         /* check for escape characters in filename */
01401         for (p_fn=*filename ; *p_fn ; p_fn++)
01402         {
01403                 if (!dazuko_printable(*p_fn))
01404                 {
01405                         found = 1;
01406                         break;
01407                 }
01408         }
01409 
01410         if (found)
01411         {
01412                 /* this is expensive, but it will also almost never occur */
01413 
01414                 p_rq = request->reply_buffer + request->reply_buffer_size_used;
01415                 limit = request->reply_buffer + request->reply_buffer_size - 1;
01416 
01417                 dazuko_snprintf(p_rq, limit - p_rq, "%s", key);
01418                 p_rq += dazuko_strlen(p_rq);
01419 
01420                 for (p_fn=*filename ; *p_fn && (p_rq<limit) ; p_fn++)
01421                 {
01422                         if (dazuko_printable(*p_fn))
01423                         {
01424                                 *p_rq = *p_fn;
01425                                 p_rq++;
01426                         }
01427                         else
01428                         {
01429                                 c = *p_fn & 0xFF;
01430                                 dazuko_snprintf(p_rq, limit - p_rq, "\\x%02x", c);
01431                                 p_rq += dazuko_strlen(p_rq);
01432                         }
01433                 }
01434 
01435                 request->reply_buffer_size_used += dazuko_strlen(request->reply_buffer + request->reply_buffer_size_used);
01436         }
01437         else
01438         {
01439                 /* no escape characters found */
01440 
01441                 dazuko_add_keyvalue_to_replybuffer(request, key, filename, 's');
01442         }
01443 }
01444 
01445 #ifdef TRUSTED_APPLICATION_SUPPORT
01446 static inline void dazuko_remove_all_trusted(struct slot_list *sl)
01447 {
01448         struct trusted_container        *tc;
01449 
01450         if (sl == NULL)
01451                 return;
01452 
01453 /* LOCK */
01454         call_xp_read_lock(&(sl->lock_trusted_list));
01455 
01456         while (sl->trusted_list != NULL)
01457         {
01458                 tc = sl->trusted_list;
01459                 sl->trusted_list = sl->trusted_list->next;
01460                 call_xp_id_free(tc->xp_id);
01461                 call_xp_free(tc->token);
01462                 call_xp_free(tc);
01463         }
01464 
01465         call_xp_read_unlock(&(sl->lock_trusted_list));
01466 /* UNLOCK */
01467 }
01468 
01469 static inline void dazuko_remove_trusted(struct slot_list *sl, char *token, int token_length)
01470 {
01471         struct trusted_container        *cur = NULL;
01472         struct trusted_container        *prev = NULL;
01473         struct trusted_container        *temp = NULL;
01474 
01475 /* LOCK */
01476         call_xp_read_lock(&(sl->lock_trusted_list));
01477 
01478         cur = sl->trusted_list;
01479         while (cur != NULL)
01480         {
01481                 if (token_length != cur->token_length)
01482                         continue;
01483 
01484                 if (memcmp(token, cur->token, token_length) == 0)
01485                 {
01486                         /* delete this container */
01487 
01488                         temp = cur;
01489 
01490                         cur = cur->next;
01491 
01492                         if (prev == NULL)
01493                         {
01494                                 sl->trusted_list = cur;
01495                         }
01496                         else
01497                         {
01498                                 prev->next = cur;
01499                         }
01500 
01501                         call_xp_id_free(temp->xp_id);
01502                         call_xp_free(temp->token);
01503                         call_xp_free(temp);
01504                 }
01505                 else
01506                 {
01507                         prev = cur;
01508                         cur = cur->next;
01509                 }
01510         }
01511 
01512         call_xp_read_unlock(&(sl->lock_trusted_list));
01513 /* UNLOCK */
01514 }
01515 #endif
01516 
01517 static int dazuko_set_option(struct daemon_id *did, int opt, void *param, int len)
01518 {
01519         /* The daemon wants to set a configuration
01520          * option in the kernel. */
01521 
01522         struct slot             *s;
01523         struct slot_list        *sl;
01524         int                     error = 0;
01525 
01526         /* sanity check */
01527         if (len < 0 || len > 8192)
01528                 return XP_ERROR_PERMISSION;
01529 
01530         /* make sure we are already registered
01531          * (or that we don't register twice) */
01532 
01533         /* find our slot */
01534         s = dazuko_find_slot_and_slotlist(did, 1, NULL, &sl);
01535 
01536         switch (opt)
01537         {
01538                 case REGISTER:
01539                         call_xp_print("dazuko: dazuko_set_option does not support REGISTER (bug!)\n");
01540                         return XP_ERROR_PERMISSION;
01541 
01542                 case UNREGISTER:
01543                         if (s == NULL)
01544                         {
01545                                 /* We are not registered! */
01546 
01547                                 return 0;
01548                         }
01549                         break;
01550 
01551                 default:
01552                         if (s == NULL)
01553                         {
01554                                 error = dazuko_register_daemon(did, "_COMPAT", 7, 1);
01555                                 if (error)
01556                                 {
01557                                         call_xp_print("dazuko: unregistered daemon %d attempted access\n", did->unique);
01558                                         return XP_ERROR_PERMISSION;
01559                                 }
01560 
01561                                 s = dazuko_find_slot_and_slotlist(did, 1, NULL, &sl);
01562                                 if (s == NULL)
01563                                 {
01564                                         call_xp_print("dazuko: unregistered daemon %d attempted access\n", did->unique);
01565                                         return XP_ERROR_PERMISSION;
01566                                 }
01567 
01568                                 call_xp_print("dazuko: warning: daemon %d is using a deprecated protocol (opt=%d)\n", did->unique, opt);
01569                         }
01570                         break;
01571         }
01572 
01573         /* check option type and take the appropriate action */
01574         switch (opt)
01575         {
01576                 case UNREGISTER:
01577                         error = _dazuko_unregister_daemon(did);
01578                         break;
01579 
01580                 case SET_ACCESS_MASK:
01581                         sl->access_mask = (char)dazuko_strtoul((char *)param);
01582 
01583                         /* rebuild access_mask_cache */
01584                         dazuko_setup_amc_cache();
01585                         break;
01586 
01587                 case ADD_INCLUDE_PATH:
01588                         error = dazuko_insert_path_fs(&(sl->incl_paths), &(sl->lock_lists), (char *)param, len);
01589                         break;
01590 
01591                 case ADD_EXCLUDE_PATH:
01592                         error = dazuko_insert_path_fs(&(sl->excl_paths), &(sl->lock_lists), (char *)param, len);
01593                         break;
01594 
01595                 case REMOVE_ALL_PATHS:
01596                         dazuko_remove_all_paths(sl);
01597                         break;
01598 
01599 #ifdef TRUSTED_APPLICATION_SUPPORT
01600                 case REMOVE_ALL_TRUSTED:
01601                         dazuko_remove_all_trusted(sl);
01602                         break;
01603 
01604                 case REMOVE_TRUSTED:
01605                         dazuko_remove_trusted(sl, (char *)param, len);
01606                         break;
01607 #endif
01608 
01609                 default:
01610                         error = XP_ERROR_INVALID;
01611                         break;
01612         }
01613 
01614         return error;
01615 }
01616 
01617 static struct slot * dazuko_get_and_hold_ready_slot(struct slot_list *sl)
01618 {
01619         /* This is a simple search to find a
01620          * slot whose state is DAZUKO_READY. This means
01621          * it is able to accept work. If a slot
01622          * is found, the slot.mutex is held so
01623          * it can be filled with work by the caller.
01624          * It is the responsibility of the caller
01625          * to RELEASE THE MUTEX. */
01626 
01627         int             i;
01628         struct slot     *s;
01629 
01630         for (i=0 ; i<NUM_SLOTS ; i++)
01631         {
01632                 s = &(sl->slots[i]);
01633 /* DOWN? */
01634                 if (dazuko_change_slot_state(s, DAZUKO_READY, DAZUKO_WAITING, 0))
01635                 {
01636 /* DOWN */
01637                         return s;
01638                 }
01639         }
01640 
01641         /* we didn't find a slot that is ready for work */
01642 
01643         return NULL;
01644 }
01645 
01646 static int get_ready_slot_condition(void *param)
01647 {
01648         return ((((struct get_ready_slot_condition_param *)param)->slot = dazuko_get_and_hold_ready_slot(((struct get_ready_slot_condition_param *)param)->slotlist)) != NULL
01649                 || call_xp_atomic_read(&(((struct get_ready_slot_condition_param *)param)->slotlist->use_count)) == 0);
01650 }
01651 
01652 static int dazuko_run_daemon_on_slotlist(unsigned long event, char *filename, int filenamelength, struct event_properties *event_p, struct file_properties *file_p, int prev_response, struct slot_list *sl)
01653 {
01654         /* This is the main function called by the kernel
01655          * to work with a daemon. */
01656 
01657         int                                             rc;
01658         int                                             unique;
01659         struct slot                                     *s;
01660         struct get_ready_slot_condition_param           cond_p1;
01661         struct two_slot_state_not_condition_param       cond_p2;
01662 
01663 begin:
01664         /* we initialize the slot value because
01665          * we cannot guarentee that it will be
01666          * assigned a new value BEFORE !active
01667          * is checked */
01668         s = NULL;
01669 
01670         /* wait for a slot to become ready */
01671         cond_p1.slotlist = sl;
01672         cond_p1.slot = s;
01673         if (call_xp_wait_until_condition(&(sl->wait_kernel_waiting_for_any_READY_slot_or_zero_use_count), get_ready_slot_condition, &cond_p1, 0) != 0)
01674         {
01675                 /* The kernel process was killed while
01676                  * waiting for a slot to become ready.
01677                  * This is fine. */
01678 
01679                 DPRINT(("dazuko: kernel process %d killed while waiting for free slot\n", event_p != NULL ? event_p->pid : 0));
01680 
01681                 return -1;  /* user interrupted */
01682         }
01683 
01684         /* Make sure we have a slot. We may have
01685          * gotten past the last wait because we
01686          * are no longer active. */
01687 
01688         s = cond_p1.slot;
01689 
01690         if (s == NULL)
01691         {
01692                 /* We were no longer active. We don't
01693                  * need to initiate a daemon. This also
01694                  * means we never acquired the lock. */
01695 
01696                 return 0;  /* allow access */
01697         }
01698 
01699 /* DOWN */
01700 
01701         /* the slot is already locked at this point */
01702 
01703         /* grab the daemon's unique */
01704         unique = s->did.unique;
01705 
01706         /* At this point we have a locked slot. It IS
01707          * sitting in the DAZUKO_WAITING state, waiting for
01708          * us to give it some work. */
01709         
01710         /* set up the slot to do work */
01711         s->filename = filename;
01712         s->event = event;
01713         s->response = prev_response;
01714         s->filenamelength = filenamelength;
01715 
01716         if (event_p == NULL)
01717                 dazuko_bzero(&(s->event_p), sizeof(struct event_properties));
01718         else
01719                 memcpy(&(s->event_p), event_p, sizeof(struct event_properties));
01720 
01721         if (file_p == NULL)
01722                 dazuko_bzero(&(s->file_p), sizeof(struct file_properties));
01723         else
01724                 memcpy(&(s->file_p), file_p, sizeof(struct file_properties));
01725 
01726         /* we are done modifying the slot */
01727         call_xp_up(&(s->mutex));
01728 /* UP */
01729 
01730         /* slot->state has changed to WAITING, notifiy appropriate queues */
01731         call_xp_notify(&(s->wait_daemon_waiting_until_this_slot_not_READY));
01732 
01733         /* wait until the daemon is finished with the slot */
01734         cond_p2.slot1 = s;
01735         cond_p2.state1 = DAZUKO_WAITING;
01736         cond_p2.slot2 = s;
01737         cond_p2.state2 = DAZUKO_WORKING;
01738         if (call_xp_wait_until_condition(&(s->wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING), two_slot_state_not_condition, &cond_p2, 0) != 0)
01739         {
01740                 /* The kernel process was killed while
01741                  * waiting for a daemon to process the file.
01742                  * This is fine. */
01743 
01744                 DPRINT(("dazuko: kernel process %d killed while waiting for daemon response\n", event_p->pid));
01745 
01746                 /* change the slot's state to let the
01747                  * daemon know we are not interested
01748                  * in a response */
01749                 dazuko_change_slot_state(s, DAZUKO_FREE, DAZUKO_FREE, 1);
01750 
01751                 /* slot->state has changed to FREE, notifiy appropriate queue */
01752                 call_xp_notify(&(s->wait_daemon_waiting_until_this_slot_not_DONE));
01753 
01754                 return -1;  /* user interrupted */
01755         }
01756 
01757         /* we are working with the slot, so
01758          * we need to lock it */
01759 /* DOWN */
01760         call_xp_down(&(s->mutex));
01761 
01762         /* make sure this is the right daemon */
01763         if (s->did.unique != unique)
01764         {
01765                 /* This is a different daemon than
01766                  * the one we assigned work to.
01767                  * We need to scan again. */
01768                 call_xp_up(&(s->mutex));
01769 /* UP */
01770                 goto begin;
01771         }
01772 
01773         /* The slot should now be in the DAZUKO_DONE state. */
01774         if (!__dazuko_change_slot_state(s, DAZUKO_DONE, DAZUKO_FREE))
01775         {
01776                 /* The daemon was killed while scanning.
01777                  * We need to scan again. */
01778 
01779                 call_xp_up(&(s->mutex));
01780 /* UP */
01781                 goto begin;
01782         }
01783 
01784         /* grab the response */
01785         rc = s->response;
01786 
01787         call_xp_up(&(s->mutex));
01788 /* UP */
01789 
01790         /* slot->state has changed to FREE, notifiy appropriate queue */
01791         call_xp_notify(&(s->wait_daemon_waiting_until_this_slot_not_DONE));
01792 
01793         /* CONGRATULATIONS! You successfully completed a full state cycle! */
01794 
01795         return rc;
01796 }
01797 
01798 static int dazuko_is_selected(struct dazuko_file_struct *kfs, struct slot_list *slist)
01799 {
01800         /* Check if the given filename (with path) is
01801          * under our include directories but not under
01802          * the exclude directories. */
01803 
01804         struct dazuko_file_listnode     *cur;
01805         struct path                     *path;
01806         int                             selected = 0;
01807         int                             use_aliases = 1;
01808 
01809         if (kfs == NULL || slist == NULL)
01810                 return 0;
01811 
01812 /* LOCK */
01813         call_xp_read_lock(&(slist->lock_lists));
01814 
01815         if (kfs->aliases == NULL && kfs->filename != NULL)
01816         {
01817                 /* extension is not using aliases */
01818 
01819                 use_aliases = 0;
01820 
01821                 kfs->aliases = (struct dazuko_file_listnode *)xp_malloc(sizeof(struct dazuko_file_listnode));
01822                 if (kfs->aliases == NULL)
01823                 {
01824                         call_xp_print("dazuko: warning: access not controlled (%s)\n", kfs->filename);
01825                         return 0;
01826                 }
01827 
01828                 dazuko_bzero(kfs->aliases, sizeof(struct dazuko_file_listnode));
01829 
01830                 kfs->aliases->filename = kfs->filename;
01831                 kfs->aliases->filename_length = kfs->filename_length;
01832         }
01833 
01834         for (cur=kfs->aliases ; cur ; cur=cur->next)
01835         {
01836                 if (cur->filename != NULL && cur->filename_length > 0)
01837                 {
01838                         /* check if filename is under our include paths */
01839                         for (path=slist->incl_paths ; path ; path=path->next)
01840                         {
01841                                 /* the include item must be at least as long as the given filename */
01842                                 if (path->len <= cur->filename_length)
01843                                 {
01844                                         /* the include item should match the beginning of the given filename */
01845                                         if (memcmp(path->path, cur->filename, path->len) == 0)
01846                                         {
01847                                                 kfs->filename = cur->filename;
01848                                                 kfs->filename_length = cur->filename_length;
01849 
01850                                                 selected = 1;
01851                                                 break;
01852                                         }
01853                                 }
01854                         }
01855 
01856                         /* If we didn't find a path, it isn't in our
01857                          * include directories. It can't be one of
01858                          * the selected files to scan. */
01859                         if (!selected)
01860                         {
01861                                 continue;
01862                         }
01863 
01864                         /* check if filename is under our exclude paths */
01865                         for (path=slist->excl_paths ; path ; path=path->next)
01866                         {
01867                                 /* the exclude item must be at least as long as the given filename */
01868                                 if (path->len <= cur->filename_length)
01869                                 {
01870                                         /* the exclude item should match the beginning of the given filename */
01871                                         if (memcmp(path->path, cur->filename, path->len) == 0)
01872                                         {
01873                                                 kfs->filename = NULL;
01874                                                 kfs->filename_length = 0;
01875 
01876                                                 selected = 0;
01877                                                 break;
01878                                         }
01879                                 }
01880                         }
01881 
01882                         /* If we are still selected, then we can stop. */
01883                         if (selected)
01884                                 break;
01885                 }
01886         }
01887 
01888         call_xp_read_unlock(&(slist->lock_lists));
01889 /* UNLOCK */
01890 
01891         if (!use_aliases)
01892         {
01893                 call_xp_free(kfs->aliases);
01894                 kfs->aliases = NULL;
01895         }
01896 
01897         return selected;
01898 }
01899 
01900 static inline int dazuko_should_scan(struct dazuko_file_struct *kfs, struct slot_list *slist)
01901 {
01902         /* Check if we are supposed to scan this file.
01903          * This checks for all the correct file types,
01904          * permissions, and if it is within the desired
01905          * paths to scan. */
01906 
01907         int result = 0;
01908 
01909         /* make necessary platform-dependent checks */
01910         if (call_xp_fill_file_struct(kfs) == 0)
01911         {
01912                 if (dazuko_is_selected(kfs, slist))
01913                         result = 1;
01914         }
01915 
01916         return result;
01917 }
01918 
01919 static inline int dazuko_run_daemon(unsigned long event, struct dazuko_file_struct *dfs, struct event_properties *event_p, struct slot_list *skip_slotlist)
01920 {
01921         struct slot_list        *sl;
01922         int                     i;
01923         int                     index;
01924         int                     j;
01925         int                     rc = 0;
01926         int                     error;
01927 
01928         i = dazuko_event2index(event);
01929         if (i < 0 || i >= NUM_EVENTS)
01930         {
01931                 call_xp_print("dazuko: unknown event:%d, allowing access (possible bug)\n", event);
01932                 return 0;
01933         }
01934 
01935         for (index=0 ; index<NUM_SLOT_LISTS ; index++)
01936         {
01937 /* DOWN */
01938                 call_xp_down(&mutex_amc);
01939 
01940                 j = access_mask_cache[i][index];
01941 
01942                 call_xp_up(&mutex_amc);
01943 /* UP */
01944 
01945                 if (j == AMC_UNSET)
01946                         break;
01947 
01948                 if (j < 0 || j >= NUM_SLOT_LISTS)
01949                 {
01950                         call_xp_print("dazuko: illegal value:%d in access_mask_cache (possible bug)\n", j);
01951                         break;
01952                 }
01953         
01954 /* DOWN */
01955                 call_xp_down(&(slot_lists[j].mutex));
01956 
01957                 sl = slot_lists[j].slot_list;
01958 
01959                 call_xp_up(&(slot_lists[j].mutex));
01960 /* UP */
01961 
01962                 if (sl == NULL)
01963                         continue;
01964 
01965                 if (sl == skip_slotlist)
01966                         continue;
01967 
01968                 if (!dazuko_should_scan(dfs, sl)) {
01969                         return 2;
01970                 }
01971 
01972                 error = dazuko_run_daemon_on_slotlist(event, dfs->filename, dfs->filename_length, event_p, &(dfs->file_p), rc, sl);
01973 
01974                 if (error < 0)
01975                 {
01976                         /* most likely user interrupt */
01977                         rc = error;
01978                         break;
01979                 }
01980                 else if (error > 0)
01981                 {
01982                         /* this daemon wants access blocked */
01983                         rc = 1;
01984                 }
01985         }
01986 
01987         return rc;
01988 }
01989 
01990 inline int dazuko_get_filename_length(const char *filename)
01991 {
01992         int len;
01993 
01994         for (len=0 ; filename[len] ; len++);
01995 
01996         return len;
01997 }
01998 
01999 static inline char* dazuko_strdup(const char *string, int *newlength)
02000 {
02001         int     length;
02002         char    *newstring;
02003 
02004         if (string == NULL)
02005                 return NULL;
02006 
02007         length = dazuko_get_filename_length(string);
02008 
02009         newstring = (char *)call_xp_malloc(length + 1);
02010 
02011         if (newstring == NULL)
02012                 return NULL;
02013 
02014         memcpy(newstring, string, length);
02015         newstring[length] = 0;
02016 
02017         if (newlength != NULL)
02018                 *newlength = length;
02019 
02020         return newstring;
02021 }
02022 
02023 #ifdef TRUSTED_APPLICATION_SUPPORT
02024 static inline int dazuko_add_trusted_daemon(struct xp_daemon_id *xp_id, const char *token, int trust_children, struct slot_list *sl)
02025 {
02026         int                             error = 0;
02027         struct trusted_container        *tc;
02028         char                            *temp;
02029 
02030 /* LOCK */
02031         call_xp_read_lock(&(sl->lock_trusted_list));
02032 
02033         tc = sl->trusted_list;
02034         while (tc != NULL)
02035         {
02036                 if (call_xp_id_compare(tc->xp_id, xp_id, 0) == DAZUKO_SAME)
02037                 {
02038                         /* This process is already registered.
02039                          * but we will assign the new token. */
02040 
02041                         temp = dazuko_strdup(token, &(tc->token_length));
02042 
02043                         if (temp != NULL)
02044                         {
02045                                 /* we only replace the token if we were able
02046                                  * to allocate the new token */
02047 
02048                                 call_xp_free(tc->token);
02049                                 tc->token = temp;
02050                         }
02051 
02052                         tc->trust_children = trust_children;
02053 
02054                         break;
02055                 }
02056                 tc = tc->next;
02057         }
02058 
02059         if (tc == NULL)
02060         {
02061                 /* we need to add the process to the list */
02062 
02063                 tc = (struct trusted_container *)call_xp_malloc(sizeof(struct trusted_container));
02064                 if (tc == NULL)
02065                 {
02066                         error = -1;
02067                 }
02068                 else
02069                 {
02070                         tc->token = dazuko_strdup(token, &(tc->token_length));
02071 
02072                         if (tc->token == NULL)
02073                         {
02074                                 error = -1;
02075                                 call_xp_free(tc);
02076                         }
02077                         else
02078                         {
02079                                 tc->xp_id = call_xp_id_copy(xp_id);
02080                                 tc->next = sl->trusted_list;
02081                                 tc->trust_children = trust_children;
02082                                 sl->trusted_list = tc;
02083 
02084                                 /* set the flag if necessary */
02085                                 if (!(sl->set_trusted_list))
02086                                         sl->set_trusted_list = 1;
02087                         }
02088                 }
02089         }
02090 
02091         call_xp_read_unlock(&(sl->lock_trusted_list));
02092 /* UNLOCK */
02093 
02094         return error;
02095 }
02096 
02097 static inline int dazuko_register_trusted_daemon(struct xp_daemon_id *xp_id, const char *group_name, char *token, char *trust_flags)
02098 {
02099         struct event_properties event_p;
02100         struct slot_list        *sl;
02101         int                     rc;
02102         int                     trust_children = 0;
02103 
02104         if (xp_id == NULL || group_name == NULL || token == NULL)
02105                 return -1;
02106 
02107         sl = find_slot_list_from_groupname(group_name);
02108 
02109         if (sl == NULL)
02110                 return -1;
02111 
02112         /* check if this group is accepting trust requests */
02113         if ((DAZUKO_TRUST_REQUEST & sl->access_mask) == 0)
02114                 return -1;
02115 
02116         memset(&event_p, 0, sizeof(event_p));
02117 
02118         /* set general event information (for example, PID) */
02119         call_xp_set_event_properties(&event_p, xp_id);
02120 
02121         if (trust_flags != NULL)
02122         {
02123                 if (dazuko_strchr(trust_flags, 'C') != NULL)
02124                 {
02125                         event_p.flags = DAZUKO_TRUST_CHILDREN;
02126                         trust_children = 1;
02127                 }
02128         }
02129 
02130         /* prev_response is set to 1 so that trust requests
02131          * are blocked by default */
02132 
02133         rc = dazuko_run_daemon_on_slotlist(DAZUKO_TRUST_REQUEST, token, dazuko_strlen(token), &event_p, NULL, 1, sl);
02134 
02135         if (rc == 0)
02136         {
02137                 /* process may be added to trusted list */
02138 
02139                 rc = dazuko_add_trusted_daemon(xp_id, token, trust_children, sl);
02140         }
02141 
02142         return rc;
02143 }
02144 
02145 static inline struct trusted_container * _remove_trusted_node(struct trusted_container *prev, struct trusted_container *cur, struct slot_list *sl)
02146 {
02147         struct trusted_container        *next;
02148 
02149         if (cur == NULL || sl == NULL)
02150                 return NULL;
02151 
02152         next = cur->next;
02153 
02154         if (prev != NULL)
02155                 prev->next = next; 
02156         else
02157                 sl->trusted_list = next;
02158 
02159         /* remove this trusted container */
02160         call_xp_id_free(cur->xp_id);
02161         call_xp_free(cur);
02162 
02163         return next;
02164 }
02165 
02166 static inline int dazuko_unregister_trusted_daemon(struct xp_daemon_id *xp_id)
02167 {
02168         struct trusted_container        *prev;
02169         struct trusted_container        *cur;
02170         int                             error = -1;
02171         int                             i;
02172         struct slot_list                *sl;
02173 
02174         for (i=0 ; i<NUM_SLOT_LISTS ; i++)
02175         {
02176 /* DOWN */
02177                 call_xp_down(&(slot_lists[i].mutex));
02178 
02179                 sl = slot_lists[i].slot_list;
02180 
02181                 call_xp_up(&(slot_lists[i].mutex));
02182 /* UP */
02183 
02184                 if (sl == NULL)
02185                         continue;
02186 
02187                 /* This boolean is not protected by a lock on purpose.
02188                  * It is used as optimization when there are no trusted
02189                  * processes. If it is set, then we will use the lock. */
02190                 if (!(sl->set_trusted_list))
02191                         continue;
02192 
02193 /* LOCK */
02194                 call_xp_read_lock(&(sl->lock_trusted_list));
02195 
02196                 prev = NULL;
02197                 cur = sl->trusted_list;
02198                 while (cur != NULL)
02199                 {
02200                         if (call_xp_id_compare(cur->xp_id, xp_id, 0) == DAZUKO_SAME)
02201                         {
02202                                 _remove_trusted_node(prev, cur, sl);
02203 
02204                                 /* we found the process and removed it */
02205                                 error = 0;
02206 
02207                                 break;
02208                         }
02209                         prev = cur;
02210                         cur = cur->next;
02211                 }
02212 
02213                 /* set flag to 0 if all trusted processes have been removed */
02214                 if (sl->trusted_list == NULL)
02215                         sl->set_trusted_list = 0;
02216 
02217                 call_xp_read_unlock(&(sl->lock_trusted_list));
02218 /* UNLOCK */
02219         }
02220 
02221         return error;
02222 }
02223 #endif
02224 
02225 static int dazuko_handle_request_register(struct dazuko_request *request, struct xp_daemon_id *xp_id)
02226 {
02227         char                    *value1;
02228         char                    *value2;
02229         int                     error = 0;
02230         struct daemon_id        did;
02231 
02232         /* read "\nRM=regmode\nGN=group" */
02233         /* send "\nID=id\nVN=versionnumber\nVS=version" */
02234 
02235         if (request->buffer_size <= 0)
02236                 return -1;
02237 
02238         if (request->reply_buffer_size <= 0)
02239                 return -1;
02240 
02241         if (dazuko_get_value("\nGN=", request->buffer, &value1) != 0)
02242                 return -1;
02243 
02244         if (dazuko_get_value("\nRM=", request->buffer, &value2) != 0)
02245         {
02246                 call_xp_free(value1);
02247                 return -1;
02248         }
02249 
02250         did.xp_id = call_xp_id_copy(xp_id);
02251         did.unique = 0; /* a unique is not yet assigned */
02252 
02253         error = dazuko_register_daemon(&did, value1, dazuko_strlen(value1), dazuko_strchr(value2, 'W') != NULL);
02254 
02255         dazuko_clear_replybuffer(request);
02256         dazuko_add_keyvalue_to_replybuffer(request, "\nID=", &(did.unique), 'd');
02257         dazuko_add_keyvalue_to_replybuffer(request, "\nVN=", &VERSION_NUMBER, 's');
02258         dazuko_add_keyvalue_to_replybuffer(request, "\nVS=", &VERSION_STRING, 's');
02259         dazuko_close_replybuffer(request);
02260 
02261         call_xp_free(value1);
02262         call_xp_free(value2);
02263         call_xp_id_free(did.xp_id);
02264 
02265         return error;
02266 }
02267 
02268 static int dazuko_handle_request_basic(struct dazuko_request *request, struct xp_daemon_id *xp_id, int basic_option)
02269 {
02270         char                    *value1;
02271         int                     error = 0;
02272         struct daemon_id        did;
02273 
02274         /* read "\nID=id" */
02275 
02276         if (request->buffer_size <= 0)
02277                 return -1;
02278 
02279         if (dazuko_get_value("\nID=", request->buffer, &value1) != 0)
02280                 return -1;
02281 
02282         did.xp_id = call_xp_id_copy(xp_id);
02283         did.unique = dazuko_strtol(value1);
02284 
02285         error = dazuko_set_option(&did, basic_option, NULL, 0);
02286 
02287         call_xp_free(value1);
02288         call_xp_id_free(did.xp_id);
02289 
02290         return error;
02291 }
02292 
02293 static int dazuko_handle_request_set_access_mask(struct dazuko_request *request, struct xp_daemon_id *xp_id)
02294 {
02295         char                    *value1;
02296         char                    *value2;
02297         int                     error = 0;
02298         struct daemon_id        did;
02299 
02300         /* read "\nID=id\nAM=mask" */
02301 
02302         if (request->buffer_size <= 0)
02303                 return -1;
02304 
02305         if (dazuko_get_value("\nID=", request->buffer, &value1) != 0)
02306                 return -1;
02307 
02308         if (dazuko_get_value("\nAM=", request->buffer, &value2) != 0)
02309         {
02310                 call_xp_free(value1);
02311                 return -1;
02312         }
02313 
02314         did.xp_id = call_xp_id_copy(xp_id);
02315         did.unique = dazuko_strtol(value1);
02316 
02317         error = dazuko_set_option(&did, SET_ACCESS_MASK, value2, dazuko_strlen(value2));
02318 
02319         call_xp_free(value1);
02320         call_xp_free(value2);
02321 
02322         return error;
02323 }
02324 
02325 static int dazuko_handle_request_add_path(struct dazuko_request *request, struct xp_daemon_id *xp_id, int add_path_option)
02326 {
02327         char                    *value1;
02328         char                    *value2;
02329         int                     error = 0;
02330         struct daemon_id        did;
02331 
02332         /* read "\nID=id\nPT=path" */
02333 
02334         if (request->buffer_size <= 0)
02335                 return -1;
02336 
02337         if (dazuko_get_value("\nID=", request->buffer, &value1) != 0)
02338                 return -1;
02339 
02340         if (dazuko_get_value("\nPT=", request->buffer, &value2) != 0)
02341         {
02342                 call_xp_free(value1);
02343                 return -1;
02344         }
02345 
02346         did.xp_id = call_xp_id_copy(xp_id);
02347         did.unique = dazuko_strtol(value1);
02348 
02349         error = dazuko_set_option(&did, add_path_option, value2, dazuko_strlen(value2));
02350 
02351         call_xp_free(value1);
02352         call_xp_free(value2);
02353         call_xp_id_free(did.xp_id);
02354 
02355         return error;
02356 }
02357 
02358 static inline int handle_event_as_readonly(struct slot *s)
02359 {
02360         /* are we in read_only mode? */
02361         if (!(s->write_mode))
02362                 return 1;
02363 
02364         /* (CLOSE events are treated as read_only since
02365          * the action is not implemented as blockable) */
02366 
02367         if (s->event == DAZUKO_ON_CLOSE || s->event == DAZUKO_ON_CLOSE_MODIFIED)
02368                 return 1;
02369 
02370         return 0;
02371 }
02372 
02373 static int dazuko_handle_request_get_an_access(struct dazuko_request *request, struct xp_daemon_id *xp_id)
02374 {
02375         char                    *value1;
02376         int                     error = 0;
02377         struct slot             *s;
02378         struct daemon_id        did;
02379 
02380         /* read "\nID=id" */
02381         /* send "\nEV=event\nFN=file\nUI=uid\nPI=pid\nFL=flags\nMD=mode..." */
02382 
02383         if (request->buffer_size <= 0)
02384                 return -1;
02385 
02386         if (request->reply_buffer_size <= 0)
02387                 return -1;
02388 
02389         if (dazuko_get_value("\nID=", request->buffer, &value1) != 0)
02390                 return -1;
02391 
02392         did.xp_id = call_xp_id_copy(xp_id);
02393         did.unique = dazuko_strtol(value1);
02394 
02395         call_xp_free(value1);
02396 
02397 /* DOWN? */
02398         s = dazuko_get_an_access(&did);
02399 
02400         if (s == NULL)
02401         {
02402                 call_xp_id_free(did.xp_id);
02403                 return XP_ERROR_INTERRUPT;
02404         }
02405 /* DOWN */
02406 
02407         /* Slot IS in DAZUKO_WORKING state. Copy all the
02408          * necessary information to userspace structure. */
02409 
02410         dazuko_clear_replybuffer(request);
02411         dazuko_add_keyvalue_to_replybuffer(request, "\nEV=", &(s->event), 'd');
02412         dazuko_add_esc_to_replybuffer(request, "\nFN=", &(s->filename));
02413 
02414         if (s->event_p.set_uid)
02415                 dazuko_add_keyvalue_to_replybuffer(request, "\nUI=", &(s->event_p.uid), 'd');
02416 
02417         if (s->event_p.set_pid)
02418                 dazuko_add_keyvalue_to_replybuffer(request, "\nPI=", &(s->event_p.pid), 'd');
02419 
02420         if (s->event_p.set_flags)
02421                 dazuko_add_keyvalue_to_replybuffer(request, "\nFL=", &(s->event_p.flags), 'd');
02422 
02423         if (s->event_p.set_mode)
02424                 dazuko_add_keyvalue_to_replybuffer(request, "\nMD=", &(s->event_p.mode), 'd');
02425 
02426         if (s->file_p.set_size)
02427                 dazuko_add_keyvalue_to_replybuffer(request, "\nFS=", &(s->file_p.size), 'l');
02428 
02429         if (s->file_p.set_uid)
02430                 dazuko_add_keyvalue_to_replybuffer(request, "\nFU=", &(s->file_p.uid), 'd');
02431 
02432         if (s->file_p.set_gid)
02433                 dazuko_add_keyvalue_to_replybuffer(request, "\nFG=", &(s->file_p.gid), 'd');
02434 
02435         if (s->file_p.set_mode)
02436                 dazuko_add_keyvalue_to_replybuffer(request, "\nFM=", &(s->file_p.mode), 'd');
02437 
02438         if (s->file_p.set_device_type)
02439                 dazuko_add_keyvalue_to_replybuffer(request, "\nDT=", &(s->file_p.device_type), 'd');
02440 
02441         dazuko_close_replybuffer(request);
02442 
02443 /* XXX: What do we do if there is a problem copying back to userspace?! */
02444 
02445         if (handle_event_as_readonly(s))
02446         {
02447                 /* the access is immediately (and at the kernel level)
02448                  * returned */
02449 
02450                 call_xp_up(&(s->mutex));
02451 /* UP */
02452 
02453                 dazuko_return_access(&did, 0, s);
02454         }
02455         else
02456         {
02457                 call_xp_up(&(s->mutex));
02458 /* UP */
02459         }
02460 
02461         call_xp_id_free(did.xp_id);
02462 
02463         return error;
02464 }
02465 
02466 static int dazuko_handle_request_return_an_access(struct dazuko_request *request, struct xp_daemon_id *xp_id)
02467 {
02468         char                    *value1;
02469         char                    *value2;
02470         int                     error = 0;
02471         struct daemon_id        did;
02472         struct slot             *s;
02473 
02474         /* read "\nID=id\nDN=deny" */
02475 
02476         if (request->buffer_size <= 0)
02477                 return -1;
02478 
02479         if (dazuko_get_value("\nID=", request->buffer, &value1) != 0)
02480                 return -1;
02481 
02482         if (dazuko_get_value("\nDN=", request->buffer, &value2) != 0)
02483         {
02484                 call_xp_free(value1);
02485                 return -1;
02486         }
02487 
02488         did.xp_id = call_xp_id_copy(xp_id);
02489         did.unique = dazuko_strtol(value1);
02490 
02491         /* find our slot */
02492         s = dazuko_find_slot(&did, 1, NULL);
02493 
02494         if (s == NULL)
02495         {
02496                 /* It appears the kernel isn't interested
02497                  * in us or our response. It gave our slot away! */
02498 
02499                 DPRINT(("dazuko: daemon %d unexpectedly lost slot (by return access)\n", did.unique));
02500 
02501                 return -1;
02502         }
02503 
02504         if (!handle_event_as_readonly(s))
02505                 error = dazuko_return_access(&did, dazuko_strtoul(value2), s);
02506 
02507         call_xp_free(value1);
02508         call_xp_free(value2);
02509         call_xp_id_free(did.xp_id);
02510 
02511         return error;
02512 }
02513 
02514 static int dazuko_handle_request_initialize_cache(struct dazuko_request *request, struct xp_daemon_id *xp_id)
02515 {
02516         char                    *value1;
02517         char                    *value2;
02518         int                     error = 0;
02519         int                     i;
02520         struct daemon_id        did;
02521 
02522         /* read "\nID=id\nCT=cachettl" */
02523 
02524         if (request->buffer_size <= 0)
02525                 return -1;
02526 
02527         if (dazuko_get_value("\nID=", request->buffer, &value1) != 0)
02528                 return -1;
02529 
02530         if (dazuko_get_value("\nCT=", request->buffer, &value2) != 0)
02531         {
02532                 call_xp_free(value1);
02533                 return -1;
02534         }
02535 
02536         did.xp_id = call_xp_id_copy(xp_id);
02537         did.unique = dazuko_strtol(value1);
02538 
02539         error = dazuko_initialize_cache(&did, dazuko_strtoul(value2));
02540 
02541         call_xp_free(value1);
02542         call_xp_free(value2);
02543 
02544         if (error)
02545                 i = 0;
02546         else
02547                 i = 1;
02548 
02549         dazuko_clear_replybuffer(request);
02550         dazuko_add_keyvalue_to_replybuffer(request, "\nCA=", &i, 'd');
02551         dazuko_close_replybuffer(request);
02552 
02553         call_xp_id_free(did.xp_id);
02554 
02555         /* the request was successful,
02556          * even if a cache is not available */
02557         return 0;
02558 }
02559 
02560 #ifdef TRUSTED_APPLICATION_SUPPORT
02561 static int dazuko_handle_request_register_trusted(struct dazuko_request *request, struct xp_daemon_id *xp_id)
02562 {
02563         char                    *value1;
02564         char                    *value2;
02565         char                    *value3 = NULL;
02566         int                     error = 0;
02567         int                     i;
02568 
02569         /* read "\nGN=group\nTT=token" */
02570         /* send "\nDN=deny" */
02571 
02572         if (request->buffer_size <= 0)
02573                 return -1;
02574 
02575         if (request->reply_buffer_size <= 0)
02576                 return -1;
02577 
02578         if (dazuko_get_value("\nGN=", request->buffer, &value1) != 0)
02579                 return -1;
02580 
02581         if (dazuko_get_value("\nTT=", request->buffer, &value2) != 0)
02582         {
02583                 call_xp_free(value1);
02584                 return -1;
02585         }
02586 
02587         dazuko_get_value("\nTF=", request->buffer, &value3);
02588 
02589         error = dazuko_register_trusted_daemon(xp_id, value1, value2, value3);
02590 
02591         if (error)
02592                 i = 1;
02593         else
02594                 i = 0;
02595 
02596         dazuko_clear_replybuffer(request);
02597         dazuko_add_keyvalue_to_replybuffer(request, "\nDN=", &i, 'd');
02598         dazuko_close_replybuffer(request);
02599 
02600         call_xp_free(value1);
02601         call_xp_free(value2);
02602         if (value3 != NULL)
02603                 call_xp_free(value3);
02604 
02605         /* the request was successful,
02606          * even if a access is denied */
02607         return 0;
02608 }
02609 
02610 static int dazuko_handle_request_remove_trusted(struct dazuko_request *request, struct xp_daemon_id *xp_id)
02611 {
02612         char                    *value1;
02613         char                    *value2;
02614         int                     error = 0;
02615         struct daemon_id        did;
02616 
02617         /* read "\nID=id\nTT=token" */
02618 
02619         if (request->buffer_size <= 0)
02620                 return -1;
02621 
02622         if (dazuko_get_value("\nID=", request->buffer, &value1) != 0)
02623                 return -1;
02624 
02625         if (dazuko_get_value("\nTT=", request->buffer, &value2) != 0)
02626         {
02627                 call_xp_free(value1);
02628                 return -1;
02629         }
02630 
02631         did.xp_id = call_xp_id_copy(xp_id);
02632         did.unique = dazuko_strtol(value1);
02633 
02634         error = dazuko_set_option(&did, REMOVE_TRUSTED, value2, dazuko_strlen(value2));
02635 
02636         call_xp_free(value1);
02637         call_xp_free(value2);
02638         call_xp_id_free(did.xp_id);
02639 
02640         return error;
02641 }
02642 
02643 #endif
02644 
02645 static int dazuko_handle_request(struct dazuko_request *request, struct xp_daemon_id *xp_id)
02646 {
02647         int     error = 0;
02648         int     type;
02649 
02650         if (request == NULL || xp_id == NULL)
02651                 return -1;
02652 
02653         type = request->type[0] + (256 * request->type[1]);
02654 
02655         switch (type)
02656         {
02657                 case REGISTER:
02658                         return dazuko_handle_request_register(request, xp_id);
02659 
02660                 case UNREGISTER:
02661                         return dazuko_handle_request_basic(request, xp_id, type);
02662 
02663                 case SET_ACCESS_MASK:
02664                         return dazuko_handle_request_set_access_mask(request, xp_id);
02665 
02666                 case ADD_INCLUDE_PATH:
02667                         return dazuko_handle_request_add_path(request, xp_id, type);
02668 
02669                 case ADD_EXCLUDE_PATH:
02670                         return dazuko_handle_request_add_path(request, xp_id, type);
02671 
02672                 case REMOVE_ALL_PATHS:
02673                         return dazuko_handle_request_basic(request, xp_id, type);
02674 
02675                 case GET_AN_ACCESS:
02676                         return dazuko_handle_request_get_an_access(request, xp_id);
02677 
02678                 case RETURN_AN_ACCESS:
02679                         return dazuko_handle_request_return_an_access(request, xp_id);
02680 
02681                 case INITIALIZE_CACHE:
02682                         return dazuko_handle_request_initialize_cache(request, xp_id);
02683 
02684 #ifdef TRUSTED_APPLICATION_SUPPORT
02685                 case REGISTER_TRUSTED:
02686                         return dazuko_handle_request_register_trusted(request, xp_id);
02687 
02688                 case UNREGISTER_TRUSTED:
02689                         /* read (nothing) */
02690 
02691                         error = dazuko_unregister_trusted_daemon(xp_id);
02692 
02693                         break;
02694 
02695                 case REMOVE_ALL_TRUSTED:
02696                         return dazuko_handle_request_basic(request, xp_id, type);
02697 
02698                 case REMOVE_TRUSTED:
02699                         return dazuko_handle_request_remove_trusted(request, xp_id);
02700 #endif
02701 
02702                 default:
02703                         error = XP_ERROR_INVALID;
02704 
02705                         break;
02706         }
02707 
02708         return error;
02709 }
02710 
02711 int dazuko_handle_user_request(const char *request_buffer, struct xp_daemon_id *xp_id)
02712 {
02713         int                     error = 0;
02714         struct dazuko_request   *user_request = NULL;
02715         unsigned char           *ll_request = NULL;
02716         unsigned char           *ll_stream = NULL;
02717         struct dazuko_request   *request = NULL;
02718         struct dazuko_request   *temp_request = NULL;
02719         char                    *value;
02720         unsigned char           tempslen[4];
02721         int                     streamlen = 0;
02722 
02723         /*
02724          * some notes on the variables: we allocate a "request" struct which
02725          * has a kernel space address and references data which is _completely_
02726          * valid from within the kernel, in addition we allocate a
02727          * "temp_request" struct which has a kernel space address and its data
02728          * mirrors the userland struct "user_request", the "ll_stream" byte
02729          * array has a kernel space address and holds a copy of the user space
02730          * request stream
02731          */
02732 
02733         if (request_buffer == NULL || xp_id == NULL)
02734                 return XP_ERROR_FAULT;
02735 
02736         if (dazuko_get_value("\nra=", request_buffer, &value) == 0)
02737         {
02738                 ll_request = (unsigned char *)dazuko_strtoul(value);
02739                 xp_free(value);
02740         }
02741         else if (dazuko_get_value("\nRA=", request_buffer, &value) == 0)
02742         {
02743                 user_request = (struct dazuko_request *)dazuko_strtoul(value);
02744                 xp_free(value);
02745         }
02746 
02747         /*
02748          * at least one kind of request presentation needs to be given (having
02749          * multiple kinds does not hurt -- we pick the most portable one and
02750          * process it)
02751          */
02752         if (ll_request == NULL && user_request == NULL)
02753                 return XP_ERROR_FAULT;
02754 
02755         /* allocate temp kernel request */
02756         temp_request = (struct dazuko_request *)call_xp_malloc(sizeof(struct dazuko_request));
02757         if (temp_request == NULL)
02758                 return XP_ERROR_FAULT;
02759 
02760         /* allocate kernel request */
02761         request = (struct dazuko_request *)call_xp_malloc(sizeof(struct dazuko_request));
02762         if (request == NULL)
02763         {
02764                 error = XP_ERROR_FAULT;
02765                 goto dazuko_handle_user_request_out;
02766         }
02767 
02768         /* request bytes are zero'd out because the "out" will check
02769          * these values */
02770         dazuko_bzero(request, sizeof(struct dazuko_request));
02771 
02772         if (ll_request != NULL)
02773         {
02774                 /*
02775                  * this is the "new style ra= (streamed) request" -- we have a
02776                  * description which is high level language independent: fill in *OUR*
02777                  * C language struct with the data we read in in a portable way
02778                  */
02779 
02780                 /* copy in the length bytes (4 bytes) */
02781                 if (call_xp_copyin(ll_request, tempslen, 4) != 0)
02782                 {
02783                         error = XP_ERROR_FAULT;
02784                         goto dazuko_handle_user_request_out;
02785                 }
02786 
02787                 if (dazuko_reqstream_chunksize(tempslen, &streamlen) != 0)
02788                 {
02789                         error = XP_ERROR_FAULT;
02790                         goto dazuko_handle_user_request_out;
02791                 }
02792 
02793                 /* allocate a buffer and copyin the stream */
02794                 ll_stream = (unsigned char *)call_xp_malloc(streamlen);
02795                 if (ll_stream == NULL)
02796                 {
02797                         error = XP_ERROR_FAULT;
02798                         goto dazuko_handle_user_request_out;
02799                 }
02800 
02801                 if (call_xp_copyin(ll_request, ll_stream, streamlen) != 0)
02802                 {
02803                         error = XP_ERROR_FAULT;
02804                         goto dazuko_handle_user_request_out;
02805                 }
02806 
02807                 /* convert the stream to into a (our) struct */
02808                 if (dazuko_reqstream_ll2hl(ll_stream, temp_request, 0) != 0)
02809                 {
02810                         error = XP_ERROR_FAULT;
02811                         goto dazuko_handle_user_request_out;
02812                 }
02813 
02814                 /* do NOT release the stream buffer here */
02815         }
02816         else if (user_request != NULL)
02817         {
02818                 /*
02819                  * this is the "old style (high level language struct) request" -- we
02820                  * HAVE TO ASSUME that the memory layout of the application and the
02821                  * kernel module match regarding the "struct dazuko_request" data type
02822                  * (yes, it's dangerous but we have no means to check anything here)
02823                  */
02824 
02825                 /* copy in the request */
02826                 if (call_xp_copyin(user_request, temp_request, sizeof(struct dazuko_request)) != 0)
02827                 {
02828                         error = XP_ERROR_FAULT;
02829                         goto dazuko_handle_user_request_out;
02830                 }
02831         }
02832 
02833         /*
02834          * at this point we have a valid request structure in "temp_request"
02835          * (still pointing to userland buffers for request and reply)
02836          */
02837 
02838         memcpy(request->type, temp_request->type, sizeof(char[2]));
02839 
02840         /* sanity check */
02841         request->buffer_size = temp_request->buffer_size;
02842         if (request->buffer_size < 0 || request->buffer_size > 8192)
02843         {
02844                 error = XP_ERROR_FAULT;
02845                 goto dazuko_handle_user_request_out;
02846         }
02847 
02848         /* sanity check */
02849         request->reply_buffer_size = temp_request->reply_buffer_size;
02850         if (request->reply_buffer_size < 0 || request->reply_buffer_size > 8192)
02851         {
02852                 error = XP_ERROR_PERMISSION;
02853                 goto dazuko_handle_user_request_out;
02854         }
02855 
02856         if (request->buffer_size > 0)
02857         {
02858                 /* allocate request command string buffer */
02859                 request->buffer = (char *)call_xp_malloc(request->buffer_size + 1);
02860                 if (request->buffer == NULL)
02861                 {
02862                         error = XP_ERROR_FAULT;
02863                         goto dazuko_handle_user_request_out;
02864                 }
02865 
02866         }
02867 
02868         if (request->reply_buffer_size > 0)
02869         {
02870                 /* allocate reply text buffer */
02871                 request->reply_buffer = (char *)call_xp_malloc(request->reply_buffer_size + 1);
02872                 if (request->reply_buffer == NULL)
02873                 {
02874                         error = XP_ERROR_FAULT;
02875                         goto dazuko_handle_user_request_out;
02876                 }
02877 
02878                 request->reply_buffer_size_used = 0;
02879         }
02880 
02881         if (request->buffer_size > 0)
02882         {
02883                 /* copy the buffer from userspace to kernelspace */
02884                 if (call_xp_copyin(temp_request->buffer, request->buffer, request->buffer_size) != 0)
02885                 {
02886                         error = XP_ERROR_FAULT;
02887                         goto dazuko_handle_user_request_out;
02888                 }
02889 
02890                 request->buffer[request->buffer_size] = 0;
02891         }
02892 
02893         /* process the request */
02894         error = dazuko_handle_request(request, xp_id);
02895 
02896         /* successfully processed and a response to be transferred back? */
02897         if (error == 0 && request->reply_buffer_size > 0)
02898         {
02899                 request->reply_buffer[request->reply_buffer_size] = 0;
02900 
02901                 temp_request->reply_buffer_size_used = request->reply_buffer_size_used;
02902 
02903                 if (ll_request != NULL)
02904                 {
02905                         /* new style (streamed) request */
02906 
02907                         /* update a few return fields */
02908                         if (dazuko_reqstream_updll(temp_request, ll_stream) != 0)
02909                         {
02910                                 error = XP_ERROR_FAULT;
02911                                 goto dazuko_handle_user_request_out;
02912                         }
02913 
02914                         /* copyout the stream back to the application */
02915                         if (call_xp_copyout(ll_stream, ll_request, streamlen) != 0)
02916                         {
02917                                 error = XP_ERROR_FAULT;
02918                                 goto dazuko_handle_user_request_out;
02919                         }
02920                 }
02921                 else if (user_request != NULL)
02922                 {
02923                         /* old style (high level language struct) request */
02924 
02925                         /* copyout the complete "struct dazuko_request" struct */
02926                         if (call_xp_copyout(temp_request, user_request, sizeof(struct dazuko_request)) != 0)
02927                         {
02928                                 error = XP_ERROR_FAULT;
02929                                 goto dazuko_handle_user_request_out;
02930                         }
02931                 }
02932 
02933                 /* transfer back the reply data itself */
02934                 if (request->reply_buffer_size_used > 0)
02935                 {
02936                         /* reply_buffer_size_used already includes the NUL byte */
02937                         if (call_xp_copyout(request->reply_buffer, temp_request->reply_buffer, request->reply_buffer_size_used) != 0)
02938                         {
02939                                 error = XP_ERROR_FAULT;
02940                                 goto dazuko_handle_user_request_out;
02941                         }
02942                 }
02943         }
02944 
02945 dazuko_handle_user_request_out:
02946 
02947         if (request != NULL)
02948         {
02949                 if (request->buffer != NULL)
02950                         call_xp_free(request->buffer);
02951 
02952                 if (request->reply_buffer != NULL)
02953                         call_xp_free(request->reply_buffer);
02954 
02955                 call_xp_free(request);
02956         }
02957 
02958         if (temp_request != NULL)
02959                 call_xp_free(temp_request);
02960 
02961         if (ll_stream != NULL)
02962                 call_xp_free(ll_stream);
02963 
02964         return error;
02965 }
02966 
02967 int dazuko_handle_user_request_compat1(void *ptr, int cmd, struct xp_daemon_id *xp_id)
02968 {
02969         struct access_compat1   *user_request_1;
02970         struct access_compat1   *temp_request_1;
02971         struct slot_list        *sl;
02972         int                     error = 0;
02973         struct slot             *s;
02974         char                    *k_param;
02975         struct daemon_id        did;
02976         int                     temp_length;
02977         int                     temp_int;
02978 
02979         if (ptr == NULL || xp_id == NULL)
02980                 return XP_ERROR_FAULT;
02981 
02982         did.xp_id = call_xp_id_copy(xp_id);
02983         did.unique = -1;
02984 
02985         switch (cmd)
02986         {
02987                 case IOCTL_GET_AN_ACCESS:
02988                         /* The daemon is requesting a filename of a file
02989                          * to scan. This code will wait until a filename
02990                          * is available, or until we should be killed.
02991                          * (killing is done if any errors occur as well
02992                          * as when the user kills us) */
02993 
02994                         user_request_1 = (struct access_compat1 *)ptr;
02995 
02996                         error = call_xp_verify_user_writable(user_request_1, sizeof(struct access_compat1));
02997                         if (error)
02998                         {
02999                                 error = XP_ERROR_FAULT;
03000                                 break;
03001                         }
03002 
03003 /* DOWN? */
03004                         s = dazuko_get_an_access(&did);
03005 
03006                         if (s == NULL)
03007                         {
03008                                 error = XP_ERROR_INTERRUPT;
03009                                 break;
03010                         }
03011 
03012 /* DOWN */
03013 
03014                         /* Slot IS in WORKING state. Copy all the
03015                          * necessary information to userspace structure. */
03016 
03017                         if (s->filenamelength >= DAZUKO_FILENAME_MAX_LENGTH_COMPAT1)
03018                         {
03019                                 /* filename length overflow :( */
03020 
03021                                 s->filename[DAZUKO_FILENAME_MAX_LENGTH_COMPAT1 - 1] = 0;
03022                                 temp_length = DAZUKO_FILENAME_MAX_LENGTH_COMPAT1;
03023                         }
03024                         else
03025                         {
03026                                 temp_length = s->filenamelength + 1;
03027                         }
03028 
03029                         temp_request_1 = (struct access_compat1 *)call_xp_malloc(sizeof(struct access_compat1));
03030                         if (temp_request_1 == NULL)
03031                         {
03032                                 error = XP_ERROR_FAULT;
03033                         }
03034                         else if (call_xp_copyin(user_request_1, temp_request_1, sizeof(struct access_compat1)) != 0)
03035                         {
03036                                 error = XP_ERROR_FAULT;
03037                         }
03038 
03039                         if (error == 0)
03040                         {
03041                                 temp_request_1->event = s->event;
03042                                 temp_request_1->o_flags = s->event_p.flags;
03043                                 temp_request_1->o_mode = s->event_p.mode;
03044                                 temp_request_1->uid = s->event_p.uid;
03045                                 temp_request_1->pid = s->event_p.pid;
03046                                 memcpy(temp_request_1->filename, s->filename, temp_length);
03047 
03048                                 if (call_xp_copyout(temp_request_1, user_request_1, sizeof(struct access_compat1)) != 0)
03049                                 {
03050                                         error = XP_ERROR_FAULT;
03051                                 }
03052                         }
03053 
03054                         call_xp_up(&(s->mutex));
03055 /* UP */
03056 
03057                         if (error)
03058                         {
03059                                 if (dazuko_change_slot_state(s, DAZUKO_WORKING, DAZUKO_BROKEN, 1))
03060                                 {
03061                                         /* slot->state has changed to BROKEN, notifiy appropriate queue */
03062                                         call_xp_notify(&(s->wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING));
03063                                 }
03064                         }
03065 
03066                         if (temp_request_1 != NULL)
03067                         {
03068                                 call_xp_free(temp_request_1);
03069                         }
03070 
03071                         break;
03072 
03073                 case IOCTL_RETURN_ACCESS:
03074                         /* The daemon has finished scanning a file
03075                          * and has the response to give. The daemon's
03076                          * slot should be in the WORKING state. */
03077 
03078                         user_request_1 = (struct access_compat1 *)ptr;
03079 
03080                         error = call_xp_verify_user_readable(user_request_1, sizeof(struct access_compat1));
03081                         if (error)
03082                         {
03083                                 error = XP_ERROR_FAULT;
03084                                 break;
03085                         }
03086 
03087                         temp_request_1 = (struct access_compat1 *)call_xp_malloc(sizeof(struct access_compat1));
03088                         if (temp_request_1 == NULL)
03089                         {
03090                                 error = XP_ERROR_FAULT;
03091                                 break;
03092                         }
03093 
03094                         if (call_xp_copyin(user_request_1, temp_request_1, sizeof(struct access_compat1)) != 0)
03095                         {
03096                                 error = XP_ERROR_FAULT;
03097                         }
03098 
03099                         temp_int = temp_request_1->deny;
03100 
03101                         call_xp_free(temp_request_1);
03102 
03103                         /* find our slot */
03104                         s = dazuko_find_slot(&did, 1, NULL);
03105 
03106                         if (s == NULL)
03107                         {
03108                                 /* It appears the kernel isn't interested
03109                                  * in us or our response. It gave our slot away! */
03110 
03111                                 DPRINT(("dazuko: daemon %d unexpectedly lost slot (by return access compat1)\n", did.unique));
03112 
03113                                 error = XP_ERROR_FAULT;
03114                         }
03115                         else if (!handle_event_as_readonly(s))
03116                         {
03117                                 error = dazuko_return_access(&did, temp_int, s);
03118                         }
03119 
03120                         break;
03121 
03122                 case IOCTL_SET_OPTION:
03123                         /* The daemon wants to set a configuration
03124                          * option in the kernel. */
03125 
03126                         error = call_xp_verify_user_readable(ptr, 2*sizeof(int));
03127                         if (error)
03128                         {
03129                                 error = XP_ERROR_FAULT;
03130                                 break;
03131                         }
03132 
03133                         /* copy option type from userspace */
03134                         if (call_xp_copyin(ptr, &temp_int, sizeof(int)) != 0)
03135                         {
03136                                 error = XP_ERROR_FAULT;
03137                                 break;
03138                         }
03139 
03140                         ptr = ((char *)ptr + sizeof(int));
03141 
03142                         /* copy path length from userspace */
03143                         if (call_xp_copyin(ptr, &temp_length, sizeof(int)) != 0)
03144                         {
03145                                 error = XP_ERROR_FAULT;
03146                                 break;
03147                         }
03148 
03149                         /* sanity check */
03150                         if (temp_length < 0 || temp_length > 4096)
03151                         {
03152                                 error = XP_ERROR_INVALID;
03153                                 break;
03154                         }
03155 
03156                         ptr = ((char *)ptr + sizeof(int));
03157 
03158                         error = call_xp_verify_user_readable(ptr, temp_length);
03159                         if (error)
03160                         {
03161                                 error = XP_ERROR_FAULT;
03162                                 break;
03163                         }
03164 
03165                         k_param = (char *)call_xp_malloc(temp_length + 1);
03166                         if (k_param == NULL)
03167                         {
03168                                 error = XP_ERROR_FAULT;
03169                                 break;
03170                         }
03171 
03172                         /* We must copy the param from userspace to kernelspace. */
03173 
03174                         if (call_xp_copyin(ptr, k_param, temp_length) != 0)
03175                         {
03176                                 call_xp_free(k_param);
03177                                 error = XP_ERROR_FAULT;
03178                                 break;
03179                         }
03180 
03181                         k_param[temp_length] = 0;
03182 
03183                         switch (temp_int)
03184                         {
03185                                 case REGISTER:
03186                                         error = dazuko_register_daemon(&did, k_param, temp_length, 1);
03187                                         break;
03188 
03189                                 case SET_ACCESS_MASK:
03190                                         /* find our slot */
03191                                         if (dazuko_find_slot_and_slotlist(&did, 1, NULL, &sl) == NULL)
03192                                         {
03193                                                 error = XP_ERROR_PERMISSION;
03194                                         }
03195                                         else if (sl == NULL)
03196                                         {
03197                                                 error = XP_ERROR_PERMISSION;
03198                                         }
03199                                         else
03200                                         {
03201                                                 sl->access_mask = k_param[0];
03202 
03203                                                 /* rebuild access_mask_cache */
03204                                                 dazuko_setup_amc_cache();
03205                                         }
03206                                         break;
03207 
03208                                 default:
03209                                         error = dazuko_set_option(&did, temp_int, k_param, temp_length);
03210                                         break;
03211                         }
03212 
03213                         call_xp_free(k_param);
03214 
03215                         break;
03216 
03217                 default:
03218                         error = XP_ERROR_INVALID;
03219 
03220                         break;
03221         }
03222 
03223         call_xp_id_free(did.xp_id);
03224 
03225         return error;
03226 }
03227 
03228 inline int dazuko_is_our_daemon(struct xp_daemon_id *xp_id, struct slot_list **slotlist)
03229 {
03230         /* Check if the current process is one
03231          * of the daemons. */
03232 
03233         int                             ret = 0;
03234         struct daemon_id                did;
03235         struct slot                     *s;
03236         int                             i;
03237         struct slot_list                *sl;
03238 #ifdef TRUSTED_APPLICATION_SUPPORT
03239         int                             cmp;
03240         struct trusted_container        *tc;
03241         struct trusted_container        *prev;
03242 #endif
03243 
03244         did.xp_id = call_xp_id_copy(xp_id);
03245         did.unique = -1;
03246 
03247         for (i=0 ; i<NUM_SLOT_LISTS ; i++)
03248         {
03249 /* DOWN */
03250                 call_xp_down(&(slot_lists[i].mutex));
03251 
03252                 sl = slot_lists[i].slot_list;
03253 
03254                 call_xp_up(&(slot_lists[i].mutex));
03255 /* UP */
03256 
03257                 if (sl == NULL)
03258                         continue;
03259 
03260                 s = _dazuko_find_slot(&did, 1, sl);
03261                 if (s != NULL)
03262                 {
03263                         ret = 1;
03264 
03265                         if (slotlist != NULL)
03266                                 *slotlist = sl;
03267 
03268                         break;
03269                 }
03270 
03271                 if (did.xp_id == NULL)
03272                         continue;
03273 
03274 #ifdef TRUSTED_APPLICATION_SUPPORT
03275                 /* This boolean is not protected by a lock on purpose.
03276                  * It is used as optimization when there are no trusted
03277                  * processes. If it is set, then we will use the lock. */
03278                 if (!(sl->set_trusted_list))
03279                         continue;
03280 
03281 /* LOCK */
03282                 call_xp_read_lock(&(sl->lock_trusted_list));
03283 
03284                 tc = sl->trusted_list;
03285                 prev = NULL;
03286                 while (tc != NULL)
03287                 {
03288                         cmp = call_xp_id_compare(tc->xp_id, did.xp_id, 1);
03289 
03290                         if (cmp == DAZUKO_SAME || (cmp == DAZUKO_CHILD && tc->trust_children))
03291                         {
03292                                 ret = 1;
03293 
03294                                 if (slotlist != NULL)
03295                                         *slotlist = sl;
03296 
03297                                 break;
03298                         }
03299                         else if (cmp == DAZUKO_SUSPICIOUS)
03300                         {
03301                                 DPRINT(("dazuko: detected suspicios activity, removing trusted daemon [%d]\n", did.unique));
03302 
03303                                 /* remove invalid trusted node */
03304                                 tc = _remove_trusted_node(prev, tc, sl);
03305                                 break;
03306                         }
03307                         else
03308                         {
03309                                 prev = tc;
03310                                 tc = tc->next;
03311                         }
03312                 }
03313 
03314                 call_xp_read_unlock(&(sl->lock_trusted_list));
03315 /* UNLOCK */
03316 
03317                 if (ret)
03318                         break;
03319 #endif
03320         }
03321 
03322         call_xp_id_free(did.xp_id);
03323 
03324         return ret;
03325 }
03326 
03327 int dazuko_check_access(unsigned long event, int daemon_is_allowed, struct xp_daemon_id *xp_id, struct slot_list **cached_lookup)
03328 {       
03329         int                     i;
03330         struct slot_list        *sl = NULL;
03331 
03332         /* do we have any daemons? */
03333         if (call_xp_atomic_read(&active) <= 0)
03334                 return -1;
03335 
03336         /* is a group interested in this event type? */
03337 
03338         i = dazuko_event2index(event);
03339         if (i < 0 || i >= NUM_EVENTS)
03340                 return -1;
03341 
03342 /* DOWN */
03343         call_xp_down(&mutex_amc);
03344 
03345         i = access_mask_cache[i][0];
03346 
03347         call_xp_up(&mutex_amc);
03348 /* UP */
03349 
03350         if (i == AMC_UNSET)
03351                 return -1;
03352 
03353         if (dazuko_is_our_daemon(xp_id, &sl))
03354         {
03355                 /* should daemons be allowed this event without a scan? */
03356                 if (daemon_is_allowed)
03357                 {
03358                         /* this is one of our daemons, so we will report as
03359                          * as if this event was not in the mask */
03360 
03361                         return -1;
03362                 }
03363                 else
03364                 {
03365                         /* this is one of our daemons, but the
03366                          * other groups must be informed */
03367 
03368                         /* if there are no other groups, allow this event */
03369                         if (call_xp_atomic_read(&groupcount) == 1)
03370                                 return -1;
03371 
03372                         if (cached_lookup != NULL)
03373                         {
03374                                 /* this slot list (ours) will be skipped */
03375                                 *cached_lookup = sl;
03376                         }
03377                 }
03378         }
03379 
03380         /* if we made it this far, then the
03381          * access should be processed */
03382 
03383         return 0;
03384 }
03385 
03386 int dazuko_process_access(unsigned long event, struct dazuko_file_struct *kfs, struct event_properties *event_p, struct slot_list *cached_lookup)
03387 {
03388         /* return codes:
03389          *   >0 -> access should be blocked
03390          *   <0 -> access should be blocked (because user interrupted)
03391          *    0 -> access is allowed
03392          *    2 -> access is not taken care of (unscanned)
03393          */
03394 
03395         int             error = 0;
03396 
03397         if (kfs == NULL)
03398         {
03399                 /* kfs is required */
03400 
03401                 call_xp_print("dazuko: kfs=NULL (possible bug)\n");
03402 
03403                 return XP_ERROR_PERMISSION;
03404         }
03405 
03406         /* check and handle this event */
03407         error = dazuko_run_daemon(event, kfs, event_p, cached_lookup);
03408         
03409         if (error == 2)
03410         {
03411                 /* access will be skipped */
03412                 return 2;
03413         }
03414         else if (error > 0)
03415         {
03416                 /* access will be blocked */
03417 
03418                 return XP_ERROR_PERMISSION;
03419         }
03420         else if (error < 0)
03421         {
03422                 /* user interrupted */
03423 
03424                 return XP_ERROR_INTERRUPT;
03425         }
03426 
03427         /* access allowed */
03428 
03429         return 0;
03430 }
03431 
03432 int dazuko_init(void)
03433 {
03434         int     i;
03435         int     error;
03436 
03437         call_xp_init_mutex(&mutex_unique_count);
03438         call_xp_init_mutex(&mutex_amc);
03439 
03440         dazuko_bzero(&slot_lists, sizeof(slot_lists));
03441 
03442         memset(&access_mask_cache, AMC_UNSET, sizeof(access_mask_cache));
03443 
03444         for (i=0 ; i<NUM_SLOT_LISTS ; i++)
03445                 call_xp_init_mutex(&(slot_lists[i].mutex));
03446 
03447         call_xp_atomic_set(&active, 0);
03448         call_xp_atomic_set(&groupcount, 0);
03449 
03450         error = call_xp_sys_hook();
03451 
03452         if (error == 0)
03453                 call_xp_print("dazuko: loaded, version=%s\n", VERSION_STRING);
03454 
03455         return error;
03456 }
03457 
03458 int dazuko_exit(void)
03459 {
03460         int     error;
03461         int     i;
03462         int     j;
03463 
03464         i = call_xp_atomic_read(&active);
03465 
03466         if (i != 0)
03467         {
03468                 call_xp_print("dazuko: warning: trying to remove Dazuko with %d process%s still registered\n", i, i==1 ? "" : "es");
03469                 return -1;
03470         }
03471 
03472         error = call_xp_sys_unhook();
03473 
03474         if (error == 0)
03475         {
03476                 call_xp_destroy_mutex(&mutex_unique_count);
03477                 call_xp_destroy_mutex(&mutex_amc);
03478 
03479                 for (i=0 ; i<NUM_SLOT_LISTS ; i++)
03480                 {
03481                         if (slot_lists[i].slot_list != NULL)
03482                         {
03483                                 dazuko_remove_all_paths(slot_lists[i].slot_list);
03484 
03485                                 if (call_xp_atomic_read(&(slot_lists[i].slot_list->use_count)) != 0)
03486                                         call_xp_print("dazuko: slot_list count was not 0 (possible bug)\n");
03487 
03488                                 for (j=0 ; j<NUM_SLOTS ; j++)
03489                                 {
03490                                         call_xp_destroy_mutex(&(slot_lists[i].slot_list->slots[j].mutex));
03491                                         call_xp_destroy_queue(&(slot_lists[i].slot_list->slots[j].wait_daemon_waiting_until_this_slot_not_READY));
03492                                         call_xp_destroy_queue(&(slot_lists[i].slot_list->slots[j].wait_kernel_waiting_until_this_slot_not_WAITING_and_not_WORKING));
03493                                         call_xp_destroy_queue(&(slot_lists[i].slot_list->slots[j].wait_daemon_waiting_until_this_slot_not_DONE));
03494                                 }
03495 
03496                                 call_xp_destroy_rwlock(&(slot_lists[i].slot_list->lock_lists));
03497 
03498 #ifdef TRUSTED_APPLICATION_SUPPORT
03499                                 dazuko_remove_all_trusted(slot_lists[i].slot_list);
03500                                 call_xp_destroy_rwlock(&(slot_lists[i].slot_list->lock_trusted_list));
03501 #endif
03502 
03503                                 call_xp_destroy_queue(&(slot_lists[i].slot_list->wait_kernel_waiting_for_any_READY_slot_or_zero_use_count));
03504 
03505                                 if (slot_lists[i].slot_list->reg_name != NULL)
03506                                         call_xp_free(slot_lists[i].slot_list->reg_name);
03507                                 slot_lists[i].slot_list->reg_name = NULL;
03508 
03509                                 call_xp_free(slot_lists[i].slot_list);
03510                                 slot_lists[i].slot_list = NULL;
03511                         }
03512 
03513                         call_xp_destroy_mutex(&(slot_lists[i].mutex));
03514                 }
03515 
03516                 call_xp_print("dazuko: unloaded, version=%s\n", VERSION_STRING);
03517         }
03518 
03519         return error;
03520 }

Generated on Sun May 21 14:30:49 2006 for RSBAC by  doxygen 1.4.2