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