net-snmp  5.4.1
vacm.c
00001 /* Portions of this file are subject to the following copyright(s).  See
00002  * the Net-SNMP's COPYING file for more details and other copyrights
00003  * that may apply:
00004  */
00005 /*
00006  * Portions of this file are copyrighted by:
00007  * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
00008  * Use is subject to license terms specified in the COPYING file
00009  * distributed with the Net-SNMP package.
00010  */
00011 
00012 /*
00013  * vacm.c
00014  *
00015  * SNMPv3 View-based Access Control Model
00016  */
00017 
00018 #include <net-snmp/net-snmp-config.h>
00019 
00020 #if HAVE_STDLIB_H
00021 #include <stdlib.h>
00022 #endif
00023 #if HAVE_STRING_H
00024 #include <string.h>
00025 #else
00026 #include <strings.h>
00027 #endif
00028 #if HAVE_UNISTD_H
00029 #include <unistd.h>
00030 #endif
00031 #include <sys/types.h>
00032 #include <stdio.h>
00033 #if TIME_WITH_SYS_TIME
00034 # ifdef WIN32
00035 #  include <sys/timeb.h>
00036 # else
00037 #  include <sys/time.h>
00038 # endif
00039 # include <time.h>
00040 #else
00041 # if HAVE_SYS_TIME_H
00042 #  include <sys/time.h>
00043 # else
00044 #  include <time.h>
00045 # endif
00046 #endif
00047 
00048 #if HAVE_WINSOCK_H
00049 #include <winsock.h>
00050 #endif
00051 
00052 #if HAVE_NETINET_IN_H
00053 #include <netinet/in.h>
00054 #endif
00055 
00056 #if HAVE_DMALLOC_H
00057 #include <dmalloc.h>
00058 #endif
00059 
00060 #include <net-snmp/types.h>
00061 #include <net-snmp/output_api.h>
00062 #include <net-snmp/config_api.h>
00063 
00064 #include <net-snmp/library/snmp_api.h>
00065 #include <net-snmp/library/vacm.h>
00066 
00067 static struct vacm_viewEntry *viewList = NULL, *viewScanPtr = NULL;
00068 static struct vacm_accessEntry *accessList = NULL, *accessScanPtr = NULL;
00069 static struct vacm_groupEntry *groupList = NULL, *groupScanPtr = NULL;
00070 
00071 /*
00072  * Macro to extend view masks with 1 bits when shorter than subtree lengths
00073  * REF: vacmViewTreeFamilyMask [RFC3415], snmpNotifyFilterMask [RFC3413]
00074  */
00075 
00076 #define VIEW_MASK(viewPtr, idx, mask) \
00077     ((idx >= viewPtr->viewMaskLen) ? mask : (viewPtr->viewMask[idx] & mask))
00078 
00084 void
00085 init_vacm(void)
00086 {
00087     /* views for access via get/set/send-notifications */
00088     se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("read"),
00089                          VACM_VIEW_READ);
00090     se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("write"),
00091                          VACM_VIEW_WRITE);
00092     se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("notify"),
00093                          VACM_VIEW_NOTIFY);
00094 
00095     /* views for permissions when receiving notifications */
00096     se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("log"),
00097                          VACM_VIEW_LOG);
00098     se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("execute"),
00099                          VACM_VIEW_EXECUTE);
00100     se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("net"),
00101                          VACM_VIEW_NET);
00102 }
00103 
00104 void
00105 vacm_save(const char *token, const char *type)
00106 {
00107     struct vacm_viewEntry *vptr;
00108     struct vacm_accessEntry *aptr;
00109     struct vacm_groupEntry *gptr;
00110     int i;
00111 
00112     for (vptr = viewList; vptr != NULL; vptr = vptr->next) {
00113         if (vptr->viewStorageType == ST_NONVOLATILE)
00114             vacm_save_view(vptr, token, type);
00115     }
00116 
00117     for (aptr = accessList; aptr != NULL; aptr = aptr->next) {
00118         if (aptr->storageType == ST_NONVOLATILE) {
00119             /* Store the standard views (if set) */
00120             if ( aptr->views[VACM_VIEW_READ  ][0] ||
00121                  aptr->views[VACM_VIEW_WRITE ][0] ||
00122                  aptr->views[VACM_VIEW_NOTIFY][0] )
00123                 vacm_save_access(aptr, token, type);
00124             /* Store any other (valid) access views */
00125             for ( i=VACM_VIEW_NOTIFY+1; i<VACM_MAX_VIEWS; i++ ) {
00126                 if ( aptr->views[i][0] )
00127                     vacm_save_auth_access(aptr, token, type, i);
00128             }
00129         }
00130     }
00131 
00132     for (gptr = groupList; gptr != NULL; gptr = gptr->next) {
00133         if (gptr->storageType == ST_NONVOLATILE)
00134             vacm_save_group(gptr, token, type);
00135     }
00136 }
00137 
00138 /*
00139  * vacm_save_view(): saves a view entry to the persistent cache 
00140  */
00141 void
00142 vacm_save_view(struct vacm_viewEntry *view, const char *token,
00143                const char *type)
00144 {
00145     char            line[4096];
00146     char           *cptr;
00147 
00148     memset(line, 0, sizeof(line));
00149     snprintf(line, sizeof(line), "%s%s %d %d %d ", token, "View",
00150             view->viewStatus, view->viewStorageType, view->viewType);
00151     line[ sizeof(line)-1 ] = 0;
00152     cptr = &line[strlen(line)]; /* the NULL */
00153 
00154     cptr =
00155         read_config_save_octet_string(cptr, (u_char *) view->viewName + 1,
00156                                       view->viewName[0]);
00157     *cptr++ = ' ';
00158     cptr =
00159         read_config_save_objid(cptr, view->viewSubtree+1,
00160                                      view->viewSubtreeLen-1);
00161     *cptr++ = ' ';
00162     cptr = read_config_save_octet_string(cptr, (u_char *) view->viewMask,
00163                                          view->viewMaskLen);
00164 
00165     read_config_store(type, line);
00166 }
00167 
00168 void
00169 vacm_parse_config_view(const char *token, char *line)
00170 {
00171     struct vacm_viewEntry view;
00172     struct vacm_viewEntry *vptr;
00173     char           *viewName = (char *) &view.viewName;
00174     oid            *viewSubtree = (oid *) & view.viewSubtree;
00175     u_char         *viewMask;
00176     size_t          len;
00177 
00178     view.viewStatus = atoi(line);
00179     line = skip_token(line);
00180     view.viewStorageType = atoi(line);
00181     line = skip_token(line);
00182     view.viewType = atoi(line);
00183     line = skip_token(line);
00184     len = sizeof(view.viewName);
00185     line =
00186         read_config_read_octet_string(line, (u_char **) & viewName, &len);
00187     view.viewSubtreeLen = MAX_OID_LEN;
00188     line =
00189         read_config_read_objid(line, (oid **) & viewSubtree,
00190                                &view.viewSubtreeLen);
00191 
00192     vptr =
00193         vacm_createViewEntry(view.viewName, view.viewSubtree,
00194                              view.viewSubtreeLen);
00195     if (!vptr) {
00196         return;
00197     }
00198 
00199     vptr->viewStatus = view.viewStatus;
00200     vptr->viewStorageType = view.viewStorageType;
00201     vptr->viewType = view.viewType;
00202     viewMask = (u_char *) vptr->viewMask;
00203     line =
00204         read_config_read_octet_string(line, (u_char **) & viewMask,
00205                                       &vptr->viewMaskLen);
00206 }
00207 
00208 /*
00209  * vacm_save_access(): saves an access entry to the persistent cache 
00210  */
00211 void
00212 vacm_save_access(struct vacm_accessEntry *access_entry, const char *token,
00213                  const char *type)
00214 {
00215     char            line[4096];
00216     char           *cptr;
00217 
00218     memset(line, 0, sizeof(line));
00219     snprintf(line, sizeof(line), "%s%s %d %d %d %d %d ",
00220             token, "Access", access_entry->status,
00221             access_entry->storageType, access_entry->securityModel,
00222             access_entry->securityLevel, access_entry->contextMatch);
00223     line[ sizeof(line)-1 ] = 0;
00224     cptr = &line[strlen(line)]; /* the NULL */
00225     cptr =
00226         read_config_save_octet_string(cptr,
00227                                       (u_char *) access_entry->groupName + 1,
00228                                       access_entry->groupName[0] + 1);
00229     *cptr++ = ' ';
00230     cptr =
00231         read_config_save_octet_string(cptr,
00232                                       (u_char *) access_entry->contextPrefix + 1,
00233                                       access_entry->contextPrefix[0] + 1);
00234 
00235     *cptr++ = ' ';
00236     cptr = read_config_save_octet_string(cptr, (u_char *) access_entry->views[VACM_VIEW_READ],
00237                                          strlen(access_entry->views[VACM_VIEW_READ]) + 1);
00238     *cptr++ = ' ';
00239     cptr =
00240         read_config_save_octet_string(cptr, (u_char *) access_entry->views[VACM_VIEW_WRITE],
00241                                       strlen(access_entry->views[VACM_VIEW_WRITE]) + 1);
00242     *cptr++ = ' ';
00243     cptr =
00244         read_config_save_octet_string(cptr, (u_char *) access_entry->views[VACM_VIEW_NOTIFY],
00245                                       strlen(access_entry->views[VACM_VIEW_NOTIFY]) + 1);
00246 
00247     read_config_store(type, line);
00248 }
00249 
00250 void
00251 vacm_save_auth_access(struct vacm_accessEntry *access_entry,
00252                       const char *token, const char *type, int authtype)
00253 {
00254     char            line[4096];
00255     char           *cptr;
00256 
00257     memset(line, 0, sizeof(line));
00258     snprintf(line, sizeof(line), "%s%s %d %d %d %d %d ",
00259             token, "AuthAccess", access_entry->status,
00260             access_entry->storageType, access_entry->securityModel,
00261             access_entry->securityLevel, access_entry->contextMatch);
00262     line[ sizeof(line)-1 ] = 0;
00263     cptr = &line[strlen(line)]; /* the NULL */
00264     cptr =
00265         read_config_save_octet_string(cptr,
00266                                       (u_char *) access_entry->groupName + 1,
00267                                       access_entry->groupName[0] + 1);
00268     *cptr++ = ' ';
00269     cptr =
00270         read_config_save_octet_string(cptr,
00271                                       (u_char *) access_entry->contextPrefix + 1,
00272                                       access_entry->contextPrefix[0] + 1);
00273 
00274     snprintf(cptr, sizeof(line)-(cptr-line), " %d ", authtype);
00275     while ( *cptr )
00276         cptr++;
00277 
00278     *cptr++ = ' ';
00279     cptr = read_config_save_octet_string(cptr,
00280                                (u_char *)access_entry->views[authtype],
00281                                   strlen(access_entry->views[authtype]) + 1);
00282 
00283     read_config_store(type, line);
00284 }
00285 
00286 char *
00287 _vacm_parse_config_access_common(struct vacm_accessEntry **aptr, char *line)
00288 {
00289     struct vacm_accessEntry access;
00290     char           *cPrefix = (char *) &access.contextPrefix;
00291     char           *gName   = (char *) &access.groupName;
00292     size_t          len;
00293 
00294     access.status = atoi(line);
00295     line = skip_token(line);
00296     access.storageType = atoi(line);
00297     line = skip_token(line);
00298     access.securityModel = atoi(line);
00299     line = skip_token(line);
00300     access.securityLevel = atoi(line);
00301     line = skip_token(line);
00302     access.contextMatch = atoi(line);
00303     line = skip_token(line);
00304     len  = sizeof(access.groupName);
00305     line = read_config_read_octet_string(line, (u_char **) &gName,   &len);
00306     len  = sizeof(access.contextPrefix);
00307     line = read_config_read_octet_string(line, (u_char **) &cPrefix, &len);
00308 
00309     *aptr = vacm_getAccessEntry(access.groupName,
00310                                   access.contextPrefix,
00311                                   access.securityModel,
00312                                   access.securityLevel);
00313     if (!*aptr)
00314         *aptr = vacm_createAccessEntry(access.groupName,
00315                                   access.contextPrefix,
00316                                   access.securityModel,
00317                                   access.securityLevel);
00318     if (!*aptr)
00319         return NULL;
00320 
00321     (*aptr)->status = access.status;
00322     (*aptr)->storageType   = access.storageType;
00323     (*aptr)->securityModel = access.securityModel;
00324     (*aptr)->securityLevel = access.securityLevel;
00325     (*aptr)->contextMatch  = access.contextMatch;
00326     return line;
00327 }
00328 
00329 void
00330 vacm_parse_config_access(const char *token, char *line)
00331 {
00332     struct vacm_accessEntry *aptr;
00333     char           *readView, *writeView, *notifyView;
00334     size_t          len;
00335 
00336     line = _vacm_parse_config_access_common(&aptr, line);
00337     if (!line)
00338         return;
00339 
00340     readView = (char *) aptr->views[VACM_VIEW_READ];
00341     len = sizeof(aptr->views[VACM_VIEW_READ]);
00342     line =
00343         read_config_read_octet_string(line, (u_char **) & readView, &len);
00344     writeView = (char *) aptr->views[VACM_VIEW_WRITE];
00345     len = sizeof(aptr->views[VACM_VIEW_WRITE]);
00346     line =
00347         read_config_read_octet_string(line, (u_char **) & writeView, &len);
00348     notifyView = (char *) aptr->views[VACM_VIEW_NOTIFY];
00349     len = sizeof(aptr->views[VACM_VIEW_NOTIFY]);
00350     line =
00351         read_config_read_octet_string(line, (u_char **) & notifyView,
00352                                       &len);
00353 }
00354 
00355 void
00356 vacm_parse_config_auth_access(const char *token, char *line)
00357 {
00358     struct vacm_accessEntry *aptr;
00359     int             authtype;
00360     char           *view;
00361     size_t          len;
00362 
00363     line = _vacm_parse_config_access_common(&aptr, line);
00364     if (!line)
00365         return;
00366 
00367     authtype = atoi(line);
00368     line = skip_token(line);
00369 
00370     view = (char *) aptr->views[authtype];
00371     len  = sizeof(aptr->views[authtype]);
00372     line = read_config_read_octet_string(line, (u_char **) & view, &len);
00373 }
00374 
00375 /*
00376  * vacm_save_group(): saves a group entry to the persistent cache 
00377  */
00378 void
00379 vacm_save_group(struct vacm_groupEntry *group_entry, const char *token,
00380                 const char *type)
00381 {
00382     char            line[4096];
00383     char           *cptr;
00384 
00385     memset(line, 0, sizeof(line));
00386     snprintf(line, sizeof(line), "%s%s %d %d %d ",
00387             token, "Group", group_entry->status,
00388             group_entry->storageType, group_entry->securityModel);
00389     line[ sizeof(line)-1 ] = 0;
00390     cptr = &line[strlen(line)]; /* the NULL */
00391 
00392     cptr =
00393         read_config_save_octet_string(cptr,
00394                                       (u_char *) group_entry->securityName + 1,
00395                                       group_entry->securityName[0] + 1);
00396     *cptr++ = ' ';
00397     cptr = read_config_save_octet_string(cptr, (u_char *) group_entry->groupName,
00398                                          strlen(group_entry->groupName) + 1);
00399 
00400     read_config_store(type, line);
00401 }
00402 
00403 void
00404 vacm_parse_config_group(const char *token, char *line)
00405 {
00406     struct vacm_groupEntry group;
00407     struct vacm_groupEntry *gptr;
00408     char           *securityName = (char *) &group.securityName;
00409     char           *groupName;
00410     size_t          len;
00411 
00412     group.status = atoi(line);
00413     line = skip_token(line);
00414     group.storageType = atoi(line);
00415     line = skip_token(line);
00416     group.securityModel = atoi(line);
00417     line = skip_token(line);
00418     len = sizeof(group.securityName);
00419     line =
00420         read_config_read_octet_string(line, (u_char **) & securityName,
00421                                       &len);
00422 
00423     gptr = vacm_createGroupEntry(group.securityModel, group.securityName);
00424     if (!gptr)
00425         return;
00426 
00427     gptr->status = group.status;
00428     gptr->storageType = group.storageType;
00429     groupName = (char *) gptr->groupName;
00430     len = sizeof(group.groupName);
00431     line =
00432         read_config_read_octet_string(line, (u_char **) & groupName, &len);
00433 }
00434 
00435 struct vacm_viewEntry *
00436 netsnmp_view_get(struct vacm_viewEntry *head, const char *viewName,
00437                   oid * viewSubtree, size_t viewSubtreeLen, int mode)
00438 {
00439     struct vacm_viewEntry *vp, *vpret = NULL;
00440     char            view[VACMSTRINGLEN];
00441     int             found, glen;
00442     int count=0;
00443 
00444     glen = (int) strlen(viewName);
00445     if (glen < 0 || glen >= VACM_MAX_STRING)
00446         return NULL;
00447     view[0] = glen;
00448     strcpy(view + 1, viewName);
00449     for (vp = head; vp; vp = vp->next) {
00450         if (!memcmp(view, vp->viewName, glen + 1)
00451             && viewSubtreeLen >= (vp->viewSubtreeLen - 1)) {
00452             int             mask = 0x80, maskpos = 0;
00453             int             oidpos;
00454             found = 1;
00455 
00456             for (oidpos = 0;
00457                  found && oidpos < (int) vp->viewSubtreeLen - 1;
00458                  oidpos++) {
00459                 if (mode==VACM_MODE_IGNORE_MASK || (VIEW_MASK(vp, maskpos, mask)) != 0) {
00460                     if (viewSubtree[oidpos] !=
00461                         vp->viewSubtree[oidpos + 1])
00462                         found = 0;
00463                 }
00464                 if (mask == 1) {
00465                     mask = 0x80;
00466                     maskpos++;
00467                 } else
00468                     mask >>= 1;
00469             }
00470 
00471             if (found) {
00472                 /*
00473                  * match successful, keep this node if its longer than
00474                  * the previous or (equal and lexicographically greater
00475                  * than the previous). 
00476                  */
00477                 count++;
00478                 if (mode == VACM_MODE_CHECK_SUBTREE) {
00479                     vpret = vp;
00480                 } else if (vpret == NULL
00481                            || vp->viewSubtreeLen > vpret->viewSubtreeLen
00482                            || (vp->viewSubtreeLen == vpret->viewSubtreeLen
00483                                && snmp_oid_compare(vp->viewSubtree + 1,
00484                                                    vp->viewSubtreeLen - 1,
00485                                                    vpret->viewSubtree + 1,
00486                                                    vpret->viewSubtreeLen - 1) >
00487                                0)) {
00488                     vpret = vp;
00489                 }
00490             }
00491         }
00492     }
00493     DEBUGMSGTL(("vacm:getView", ", %s\n", (vpret) ? "found" : "none"));
00494     if (mode == VACM_MODE_CHECK_SUBTREE && count > 1) {
00495         return NULL;
00496     }
00497     return vpret;
00498 }
00499 
00500 /*******************************************************************o-o******
00501  * vacm_checkSubtree
00502  *
00503  * Check to see if everything within a subtree is in view, not in view,
00504  * or possibly both.
00505  *
00506  * Parameters:
00507  *   *viewName           - Name of view to check
00508  *   *viewSubtree        - OID of subtree
00509  *    viewSubtreeLen     - length of subtree OID
00510  *      
00511  * Returns:
00512  *   VACM_SUCCESS          The OID is included in the view.
00513  *   VACM_NOTINVIEW        If no entry in the view list includes the
00514  *                         provided OID, or the OID is explicitly excluded
00515  *                         from the view. 
00516  *   VACM_SUBTREE_UNKNOWN  The entire subtree has both allowed and disallowed
00517  *                         portions.
00518  */
00519 int
00520 netsnmp_view_subtree_check(struct vacm_viewEntry *head, const char *viewName,
00521                            oid * viewSubtree, size_t viewSubtreeLen)
00522 {
00523     struct vacm_viewEntry *vp, *vpShorter = NULL, *vpLonger = NULL;
00524     char            view[VACMSTRINGLEN];
00525     int             found, glen;
00526 
00527     glen = (int) strlen(viewName);
00528     if (glen < 0 || glen >= VACM_MAX_STRING)
00529         return VACM_NOTINVIEW;
00530     view[0] = glen;
00531     strcpy(view + 1, viewName);
00532     DEBUGMSGTL(("9:vacm:checkSubtree", "view %s\n", viewName));
00533     for (vp = head; vp; vp = vp->next) {
00534         if (!memcmp(view, vp->viewName, glen + 1)) {
00535             /*
00536              * If the subtree defined in the view is shorter than or equal
00537              * to the subtree we are comparing, then it might envelop the
00538              * subtree we are comparing against.
00539              */
00540             if (viewSubtreeLen >= (vp->viewSubtreeLen - 1)) {
00541                 int             mask = 0x80, maskpos = 0;
00542                 int             oidpos;
00543                 found = 1;
00544 
00545                 /*
00546                  * check the mask
00547                  */
00548                 for (oidpos = 0;
00549                      found && oidpos < (int) vp->viewSubtreeLen - 1;
00550                      oidpos++) {
00551                     if (VIEW_MASK(vp, maskpos, mask) != 0) {
00552                         if (viewSubtree[oidpos] !=
00553                             vp->viewSubtree[oidpos + 1])
00554                             found = 0;
00555                     }
00556                     if (mask == 1) {
00557                         mask = 0x80;
00558                         maskpos++;
00559                     } else
00560                         mask >>= 1;
00561                 }
00562 
00563                 if (found) {
00564                     /*
00565                      * match successful, keep this node if it's longer than
00566                      * the previous or (equal and lexicographically greater
00567                      * than the previous). 
00568                      */
00569                     DEBUGMSGTL(("9:vacm:checkSubtree", " %s matched?\n", vp->viewName));
00570     
00571                     if (vpShorter == NULL
00572                         || vp->viewSubtreeLen > vpShorter->viewSubtreeLen
00573                         || (vp->viewSubtreeLen == vpShorter->viewSubtreeLen
00574                            && snmp_oid_compare(vp->viewSubtree + 1,
00575                                                vp->viewSubtreeLen - 1,
00576                                                vpShorter->viewSubtree + 1,
00577                                                vpShorter->viewSubtreeLen - 1) >
00578                                    0)) {
00579                         vpShorter = vp;
00580                     }
00581                 }
00582             }
00583             /*
00584              * If the subtree defined in the view is longer than the
00585              * subtree we are comparing, then it might ambiguate our
00586              * response.
00587              */
00588             else {
00589                 int             mask = 0x80, maskpos = 0;
00590                 int             oidpos;
00591                 found = 1;
00592 
00593                 /*
00594                  * check the mask up to the length of the provided subtree
00595                  */
00596                 for (oidpos = 0;
00597                      found && oidpos < (int) viewSubtreeLen;
00598                      oidpos++) {
00599                     if (VIEW_MASK(vp, maskpos, mask) != 0) {
00600                         if (viewSubtree[oidpos] !=
00601                             vp->viewSubtree[oidpos + 1])
00602                             found = 0;
00603                     }
00604                     if (mask == 1) {
00605                         mask = 0x80;
00606                         maskpos++;
00607                     } else
00608                         mask >>= 1;
00609                 }
00610 
00611                 if (found) {
00612                     /*
00613                      * match successful.  If we already found a match
00614                      * with a different view type, then parts of the subtree 
00615                      * are included and others are excluded, so return UNKNOWN.
00616                      */
00617                     DEBUGMSGTL(("9:vacm:checkSubtree", " %s matched?\n", vp->viewName));
00618                     if (vpLonger != NULL
00619                         && (vpLonger->viewType != vp->viewType)) {
00620                         DEBUGMSGTL(("vacm:checkSubtree", ", %s\n", "unknown"));
00621                         return VACM_SUBTREE_UNKNOWN;
00622                     }
00623                     else if (vpLonger == NULL) {
00624                         vpLonger = vp;
00625                     }
00626                 }
00627             }
00628         }
00629     }
00630     DEBUGMSGTL(("9:vacm:checkSubtree", " %s matched\n", vp->viewName));
00631 
00632     /*
00633      * If we found a matching view subtree with a longer OID than the provided
00634      * OID, check to see if its type is consistent with any matching view
00635      * subtree we may have found with a shorter OID than the provided OID.
00636      *
00637      * The view type of the longer OID is inconsistent with the shorter OID in
00638      * either of these two cases:
00639      *  1) No matching shorter OID was found and the view type of the longer
00640      *     OID is INCLUDE.
00641      *  2) A matching shorter ID was found and its view type doesn't match
00642      *     the view type of the longer OID.
00643      */
00644     if (vpLonger != NULL) {
00645         if ((!vpShorter && vpLonger->viewType != SNMP_VIEW_EXCLUDED)
00646             || (vpShorter && vpLonger->viewType != vpShorter->viewType)) {
00647             DEBUGMSGTL(("vacm:checkSubtree", ", %s\n", "unknown"));
00648             return VACM_SUBTREE_UNKNOWN;
00649         }
00650     }
00651 
00652     if (vpShorter && vpShorter->viewType != SNMP_VIEW_EXCLUDED) {
00653         DEBUGMSGTL(("vacm:checkSubtree", ", %s\n", "included"));
00654         return VACM_SUCCESS;
00655     }
00656 
00657     DEBUGMSGTL(("vacm:checkSubtree", ", %s\n", "excluded"));
00658     return VACM_NOTINVIEW;
00659 }
00660 
00661 void
00662 vacm_scanViewInit(void)
00663 {
00664     viewScanPtr = viewList;
00665 }
00666 
00667 struct vacm_viewEntry *
00668 vacm_scanViewNext(void)
00669 {
00670     struct vacm_viewEntry *returnval = viewScanPtr;
00671     if (viewScanPtr)
00672         viewScanPtr = viewScanPtr->next;
00673     return returnval;
00674 }
00675 
00676 struct vacm_viewEntry *
00677 netsnmp_view_create(struct vacm_viewEntry **head, const char *viewName,
00678                      oid * viewSubtree, size_t viewSubtreeLen)
00679 {
00680     struct vacm_viewEntry *vp, *lp, *op = NULL;
00681     int             cmp, cmp2, glen;
00682 
00683     glen = (int) strlen(viewName);
00684     if (glen < 0 || glen >= VACM_MAX_STRING)
00685         return NULL;
00686     vp = (struct vacm_viewEntry *) calloc(1,
00687                                           sizeof(struct vacm_viewEntry));
00688     if (vp == NULL)
00689         return NULL;
00690     vp->reserved =
00691         (struct vacm_viewEntry *) calloc(1, sizeof(struct vacm_viewEntry));
00692     if (vp->reserved == NULL) {
00693         free(vp);
00694         return NULL;
00695     }
00696 
00697     vp->viewName[0] = glen;
00698     strcpy(vp->viewName + 1, viewName);
00699     vp->viewSubtree[0] = viewSubtreeLen;
00700     memcpy(vp->viewSubtree + 1, viewSubtree, viewSubtreeLen * sizeof(oid));
00701     vp->viewSubtreeLen = viewSubtreeLen + 1;
00702 
00703     lp = *head;
00704     while (lp) {
00705         cmp = memcmp(lp->viewName, vp->viewName, glen + 1);
00706         cmp2 = snmp_oid_compare(lp->viewSubtree, lp->viewSubtreeLen,
00707                                 vp->viewSubtree, vp->viewSubtreeLen);
00708         if (cmp == 0 && cmp2 > 0)
00709             break;
00710         if (cmp > 0)
00711             break;
00712         op = lp;
00713         lp = lp->next;
00714     }
00715     vp->next = lp;
00716     if (op)
00717         op->next = vp;
00718     else
00719         *head = vp;
00720     return vp;
00721 }
00722 
00723 void
00724 netsnmp_view_destroy(struct vacm_viewEntry **head, const char *viewName,
00725                       oid * viewSubtree, size_t viewSubtreeLen)
00726 {
00727     struct vacm_viewEntry *vp, *lastvp = NULL;
00728 
00729     if ((*head) && !strcmp((*head)->viewName + 1, viewName)
00730         && (*head)->viewSubtreeLen == viewSubtreeLen
00731         && !memcmp((char *) (*head)->viewSubtree, (char *) viewSubtree,
00732                    viewSubtreeLen * sizeof(oid))) {
00733         vp = (*head);
00734         (*head) = (*head)->next;
00735     } else {
00736         for (vp = (*head); vp; vp = vp->next) {
00737             if (!strcmp(vp->viewName + 1, viewName)
00738                 && vp->viewSubtreeLen == viewSubtreeLen
00739                 && !memcmp((char *) vp->viewSubtree, (char *) viewSubtree,
00740                            viewSubtreeLen * sizeof(oid)))
00741                 break;
00742             lastvp = vp;
00743         }
00744         if (!vp || !lastvp)
00745             return;
00746         lastvp->next = vp->next;
00747     }
00748     if (vp->reserved)
00749         free(vp->reserved);
00750     free(vp);
00751     return;
00752 }
00753 
00754 void
00755 netsnmp_view_clear(struct vacm_viewEntry **head)
00756 {
00757     struct vacm_viewEntry *vp;
00758     while ((vp = (*head))) {
00759         (*head) = vp->next;
00760         if (vp->reserved)
00761             free(vp->reserved);
00762         free(vp);
00763     }
00764 }
00765 
00766 struct vacm_groupEntry *
00767 vacm_getGroupEntry(int securityModel, const char *securityName)
00768 {
00769     struct vacm_groupEntry *vp;
00770     char            secname[VACMSTRINGLEN];
00771     int             glen;
00772 
00773     glen = (int) strlen(securityName);
00774     if (glen < 0 || glen >= VACM_MAX_STRING)
00775         return NULL;
00776     secname[0] = glen;
00777     strcpy(secname + 1, securityName);
00778 
00779     for (vp = groupList; vp; vp = vp->next) {
00780         if ((securityModel == vp->securityModel
00781              || vp->securityModel == SNMP_SEC_MODEL_ANY)
00782             && !memcmp(vp->securityName, secname, glen + 1))
00783             return vp;
00784     }
00785     return NULL;
00786 }
00787 
00788 void
00789 vacm_scanGroupInit(void)
00790 {
00791     groupScanPtr = groupList;
00792 }
00793 
00794 struct vacm_groupEntry *
00795 vacm_scanGroupNext(void)
00796 {
00797     struct vacm_groupEntry *returnval = groupScanPtr;
00798     if (groupScanPtr)
00799         groupScanPtr = groupScanPtr->next;
00800     return returnval;
00801 }
00802 
00803 struct vacm_groupEntry *
00804 vacm_createGroupEntry(int securityModel, const char *securityName)
00805 {
00806     struct vacm_groupEntry *gp, *lg, *og;
00807     int             cmp, glen;
00808 
00809     glen = (int) strlen(securityName);
00810     if (glen < 0 || glen >= VACM_MAX_STRING)
00811         return NULL;
00812     gp = (struct vacm_groupEntry *) calloc(1,
00813                                            sizeof(struct vacm_groupEntry));
00814     if (gp == NULL)
00815         return NULL;
00816     gp->reserved =
00817         (struct vacm_groupEntry *) calloc(1,
00818                                           sizeof(struct vacm_groupEntry));
00819     if (gp->reserved == NULL) {
00820         free(gp);
00821         return NULL;
00822     }
00823 
00824     gp->securityModel = securityModel;
00825     gp->securityName[0] = glen;
00826     strcpy(gp->securityName + 1, securityName);
00827 
00828     lg = groupList;
00829     og = NULL;
00830     while (lg) {
00831         if (lg->securityModel > securityModel)
00832             break;
00833         if (lg->securityModel == securityModel &&
00834             (cmp =
00835              memcmp(lg->securityName, gp->securityName, glen + 1)) > 0)
00836             break;
00837         /*
00838          * if (lg->securityModel == securityModel && cmp == 0) abort(); 
00839          */
00840         og = lg;
00841         lg = lg->next;
00842     }
00843     gp->next = lg;
00844     if (og == NULL)
00845         groupList = gp;
00846     else
00847         og->next = gp;
00848     return gp;
00849 }
00850 
00851 void
00852 vacm_destroyGroupEntry(int securityModel, const char *securityName)
00853 {
00854     struct vacm_groupEntry *vp, *lastvp = NULL;
00855 
00856     if (groupList && groupList->securityModel == securityModel
00857         && !strcmp(groupList->securityName + 1, securityName)) {
00858         vp = groupList;
00859         groupList = groupList->next;
00860     } else {
00861         for (vp = groupList; vp; vp = vp->next) {
00862             if (vp->securityModel == securityModel
00863                 && !strcmp(vp->securityName + 1, securityName))
00864                 break;
00865             lastvp = vp;
00866         }
00867         if (!vp || !lastvp)
00868             return;
00869         lastvp->next = vp->next;
00870     }
00871     if (vp->reserved)
00872         free(vp->reserved);
00873     free(vp);
00874     return;
00875 }
00876 
00877 void
00878 vacm_destroyAllGroupEntries(void)
00879 {
00880     struct vacm_groupEntry *gp;
00881     while ((gp = groupList)) {
00882         groupList = gp->next;
00883         if (gp->reserved)
00884             free(gp->reserved);
00885         free(gp);
00886     }
00887 }
00888 
00889 struct vacm_accessEntry *
00890 vacm_getAccessEntry(const char *groupName,
00891                     const char *contextPrefix,
00892                     int securityModel, int securityLevel)
00893 {
00894     struct vacm_accessEntry *vp;
00895     char            group[VACMSTRINGLEN];
00896     char            context[VACMSTRINGLEN];
00897     int             glen, clen;
00898 
00899     glen = (int) strlen(groupName);
00900     if (glen < 0 || glen >= VACM_MAX_STRING)
00901         return NULL;
00902     clen = (int) strlen(contextPrefix);
00903     if (clen < 0 || clen >= VACM_MAX_STRING)
00904         return NULL;
00905 
00906     group[0] = glen;
00907     strcpy(group + 1, groupName);
00908     context[0] = clen;
00909     strcpy(context + 1, contextPrefix);
00910     for (vp = accessList; vp; vp = vp->next) {
00911         if ((securityModel == vp->securityModel
00912              || vp->securityModel == SNMP_SEC_MODEL_ANY)
00913             && securityLevel >= vp->securityLevel
00914             && !memcmp(vp->groupName, group, glen + 1)
00915             &&
00916             ((vp->contextMatch == CONTEXT_MATCH_EXACT
00917               && clen == vp->contextPrefix[0]
00918               && (memcmp(vp->contextPrefix, context, clen + 1) == 0))
00919              || (vp->contextMatch == CONTEXT_MATCH_PREFIX
00920                  && clen >= vp->contextPrefix[0]
00921                  && (memcmp(vp->contextPrefix + 1, context + 1,
00922                             vp->contextPrefix[0]) == 0))))
00923             return vp;
00924     }
00925     return NULL;
00926 }
00927 
00928 void
00929 vacm_scanAccessInit(void)
00930 {
00931     accessScanPtr = accessList;
00932 }
00933 
00934 struct vacm_accessEntry *
00935 vacm_scanAccessNext(void)
00936 {
00937     struct vacm_accessEntry *returnval = accessScanPtr;
00938     if (accessScanPtr)
00939         accessScanPtr = accessScanPtr->next;
00940     return returnval;
00941 }
00942 
00943 struct vacm_accessEntry *
00944 vacm_createAccessEntry(const char *groupName,
00945                        const char *contextPrefix,
00946                        int securityModel, int securityLevel)
00947 {
00948     struct vacm_accessEntry *vp, *lp, *op = NULL;
00949     int             cmp, glen, clen;
00950 
00951     glen = (int) strlen(groupName);
00952     if (glen < 0 || glen >= VACM_MAX_STRING)
00953         return NULL;
00954     clen = (int) strlen(contextPrefix);
00955     if (clen < 0 || clen >= VACM_MAX_STRING)
00956         return NULL;
00957     vp = (struct vacm_accessEntry *) calloc(1,
00958                                             sizeof(struct
00959                                                    vacm_accessEntry));
00960     if (vp == NULL)
00961         return NULL;
00962     vp->reserved =
00963         (struct vacm_accessEntry *) calloc(1,
00964                                            sizeof(struct
00965                                                   vacm_accessEntry));
00966     if (vp->reserved == NULL) {
00967         free(vp);
00968         return NULL;
00969     }
00970 
00971     vp->securityModel = securityModel;
00972     vp->securityLevel = securityLevel;
00973     vp->groupName[0] = glen;
00974     strcpy(vp->groupName + 1, groupName);
00975     vp->contextPrefix[0] = clen;
00976     strcpy(vp->contextPrefix + 1, contextPrefix);
00977 
00978     lp = accessList;
00979     while (lp) {
00980         cmp = memcmp(lp->groupName, vp->groupName, glen + 1);
00981         if (cmp > 0)
00982             break;
00983         if (cmp < 0)
00984             goto next;
00985         cmp = memcmp(lp->contextPrefix, vp->contextPrefix, clen + 1);
00986         if (cmp > 0)
00987             break;
00988         if (cmp < 0)
00989             goto next;
00990         if (lp->securityModel > securityModel)
00991             break;
00992         if (lp->securityModel < securityModel)
00993             goto next;
00994         if (lp->securityLevel > securityLevel)
00995             break;
00996       next:
00997         op = lp;
00998         lp = lp->next;
00999     }
01000     vp->next = lp;
01001     if (op == NULL)
01002         accessList = vp;
01003     else
01004         op->next = vp;
01005     return vp;
01006 }
01007 
01008 void
01009 vacm_destroyAccessEntry(const char *groupName,
01010                         const char *contextPrefix,
01011                         int securityModel, int securityLevel)
01012 {
01013     struct vacm_accessEntry *vp, *lastvp = NULL;
01014 
01015     if (accessList && accessList->securityModel == securityModel
01016         && accessList->securityLevel == securityLevel
01017         && !strcmp(accessList->groupName + 1, groupName)
01018         && !strcmp(accessList->contextPrefix + 1, contextPrefix)) {
01019         vp = accessList;
01020         accessList = accessList->next;
01021     } else {
01022         for (vp = accessList; vp; vp = vp->next) {
01023             if (vp->securityModel == securityModel
01024                 && vp->securityLevel == securityLevel
01025                 && !strcmp(vp->groupName + 1, groupName)
01026                 && !strcmp(vp->contextPrefix + 1, contextPrefix))
01027                 break;
01028             lastvp = vp;
01029         }
01030         if (!vp || !lastvp)
01031             return;
01032         lastvp->next = vp->next;
01033     }
01034     if (vp->reserved)
01035         free(vp->reserved);
01036     free(vp);
01037     return;
01038 }
01039 
01040 void
01041 vacm_destroyAllAccessEntries(void)
01042 {
01043     struct vacm_accessEntry *ap;
01044     while ((ap = accessList)) {
01045         accessList = ap->next;
01046         if (ap->reserved)
01047             free(ap->reserved);
01048         free(ap);
01049     }
01050 }
01051 
01052 int
01053 store_vacm(int majorID, int minorID, void *serverarg, void *clientarg)
01054 {
01055     /*
01056      * figure out our application name 
01057      */
01058     char           *appname = (char *) clientarg;
01059     if (appname == NULL) {
01060         appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
01061                                         NETSNMP_DS_LIB_APPTYPE);
01062     }
01063 
01064     /*
01065      * save the VACM MIB 
01066      */
01067     vacm_save("vacm", appname);
01068     return SNMPERR_SUCCESS;
01069 }
01070 
01071 /*
01072  * returns 1 if vacm has *any* (non-built-in) configuration entries,
01073  * regardless of whether or not there is enough to make a decision,
01074  * else return 0 
01075  */
01076 int
01077 vacm_is_configured(void)
01078 {
01079     if (accessList == NULL && groupList == NULL) {
01080         return 0;
01081     }
01082     return 1;
01083 }
01084 
01085 /*
01086  * backwards compatability
01087  */
01088 struct vacm_viewEntry *
01089 vacm_getViewEntry(const char *viewName,
01090                   oid * viewSubtree, size_t viewSubtreeLen, int mode)
01091 {
01092     return netsnmp_view_get( viewList, viewName, viewSubtree, viewSubtreeLen,
01093                              mode);
01094 }
01095 
01096 int
01097 vacm_checkSubtree(const char *viewName,
01098                   oid * viewSubtree, size_t viewSubtreeLen)
01099 {
01100     return netsnmp_view_subtree_check( viewList, viewName, viewSubtree,
01101                                        viewSubtreeLen);
01102 }
01103 
01104 struct vacm_viewEntry *
01105 vacm_createViewEntry(const char *viewName,
01106                      oid * viewSubtree, size_t viewSubtreeLen)
01107 {
01108     return netsnmp_view_create( &viewList, viewName, viewSubtree,
01109                                 viewSubtreeLen);
01110 }
01111 
01112 void
01113 vacm_destroyViewEntry(const char *viewName,
01114                       oid * viewSubtree, size_t viewSubtreeLen)
01115 {
01116     netsnmp_view_destroy( &viewList, viewName, viewSubtree, viewSubtreeLen);
01117 }
01118 
01119 void
01120 vacm_destroyAllViewEntries(void)
01121 {
01122     netsnmp_view_clear( &viewList );
01123 }
01124