]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/net/snmp/agent/v2_0/src/mibgroup/snmpv3/usmUser.c
Initial revision
[karo-tx-redboot.git] / packages / net / snmp / agent / v2_0 / src / mibgroup / snmpv3 / usmUser.c
1 //==========================================================================
2 //
3 //      ./agent/current/src/mibgroup/snmpv3/usmUser.c
4 //
5 //
6 //==========================================================================
7 //####ECOSGPLCOPYRIGHTBEGIN####
8 // -------------------------------------------
9 // This file is part of eCos, the Embedded Configurable Operating System.
10 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
11 //
12 // eCos is free software; you can redistribute it and/or modify it under
13 // the terms of the GNU General Public License as published by the Free
14 // Software Foundation; either version 2 or (at your option) any later version.
15 //
16 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19 // for more details.
20 //
21 // You should have received a copy of the GNU General Public License along
22 // with eCos; if not, write to the Free Software Foundation, Inc.,
23 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
24 //
25 // As a special exception, if other files instantiate templates or use macros
26 // or inline functions from this file, or you compile this file and link it
27 // with other works to produce a work based on this file, this file does not
28 // by itself cause the resulting work to be covered by the GNU General Public
29 // License. However the source code for this file must still be made available
30 // in accordance with section (3) of the GNU General Public License.
31 //
32 // This exception does not invalidate any other reasons why a work based on
33 // this file might be covered by the GNU General Public License.
34 //
35 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
36 // at http://sources.redhat.com/ecos/ecos-license/
37 // -------------------------------------------
38 //####ECOSGPLCOPYRIGHTEND####
39 //####UCDSNMPCOPYRIGHTBEGIN####
40 //
41 // -------------------------------------------
42 //
43 // Portions of this software may have been derived from the UCD-SNMP
44 // project,  <http://ucd-snmp.ucdavis.edu/>  from the University of
45 // California at Davis, which was originally based on the Carnegie Mellon
46 // University SNMP implementation.  Portions of this software are therefore
47 // covered by the appropriate copyright disclaimers included herein.
48 //
49 // The release used was version 4.1.2 of May 2000.  "ucd-snmp-4.1.2"
50 // -------------------------------------------
51 //
52 //####UCDSNMPCOPYRIGHTEND####
53 //==========================================================================
54 //#####DESCRIPTIONBEGIN####
55 //
56 // Author(s):    Andrew.Lunn@ascom.ch, Manu.Sharma@ascom.com
57 // Contributors: hmt
58 // Date:         2001-05-29
59 // Purpose:      Port of UCD-SNMP distribution to eCos.
60 // Description:  
61 //              
62 //
63 //####DESCRIPTIONEND####
64 //
65 //==========================================================================
66 /********************************************************************
67        Copyright 1989, 1991, 1992 by Carnegie Mellon University
68
69                           Derivative Work -
70 Copyright 1996, 1998, 1999, 2000 The Regents of the University of California
71
72                          All Rights Reserved
73
74 Permission to use, copy, modify and distribute this software and its
75 documentation for any purpose and without fee is hereby granted,
76 provided that the above copyright notice appears in all copies and
77 that both that copyright notice and this permission notice appear in
78 supporting documentation, and that the name of CMU and The Regents of
79 the University of California not be used in advertising or publicity
80 pertaining to distribution of the software without specific written
81 permission.
82
83 CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL
84 WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
85 WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL CMU OR
86 THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL,
87 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
88 FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
89 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
90 CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
91 *********************************************************************/
92 /* 
93  * usmUser.c
94  */
95
96 #include <config.h>
97
98 #ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
99 #include <stdlib.h>
100
101 #if HAVE_STRING_H
102 #include <string.h>
103 #else
104 #include <strings.h>
105 #endif
106
107 #if HAVE_WINSOCK_H
108 #include <winsock.h>
109 #endif
110
111 #include "mibincl.h"
112 #include "snmpusm.h"
113 #include "snmpv3.h"
114 #include "snmp-tc.h"
115 #include "read_config.h"
116 #include "agent_read_config.h"
117 //#include "util_funcs.h"
118 #include "keytools.h"
119 #include "tools.h"
120 #include "scapi.h"
121
122 #include "usmUser.h"
123 #include "transform_oids.h"
124
125 struct variable4 usmUser_variables[] = {
126   { USMUSERSPINLOCK     , ASN_INTEGER   , RWRITE, var_usmUser, 1, { 1 } },
127   { USMUSERSECURITYNAME , ASN_OCTET_STR , RONLY , var_usmUser, 3, { 2,1,3 } },
128   { USMUSERCLONEFROM    , ASN_OBJECT_ID , RWRITE, var_usmUser, 3, { 2,1,4 } },
129   { USMUSERAUTHPROTOCOL , ASN_OBJECT_ID , RWRITE, var_usmUser, 3, { 2,1,5 } },
130   { USMUSERAUTHKEYCHANGE, ASN_OCTET_STR , RWRITE, var_usmUser, 3, { 2,1,6 } },
131   { USMUSEROWNAUTHKEYCHANGE, ASN_OCTET_STR , RWRITE, var_usmUser, 3, { 2,1,7 } },
132   { USMUSERPRIVPROTOCOL , ASN_OBJECT_ID , RWRITE, var_usmUser, 3, { 2,1,8 } },
133   { USMUSERPRIVKEYCHANGE, ASN_OCTET_STR , RWRITE, var_usmUser, 3, { 2,1,9 } },
134   { USMUSEROWNPRIVKEYCHANGE, ASN_OCTET_STR , RWRITE, var_usmUser, 3, { 2,1,10 } },
135   { USMUSERPUBLIC       , ASN_OCTET_STR , RWRITE, var_usmUser, 3, { 2,1,11 } },
136   { USMUSERSTORAGETYPE  , ASN_INTEGER   , RWRITE, var_usmUser, 3, { 2,1,12 } },
137   { USMUSERSTATUS       , ASN_INTEGER   , RWRITE, var_usmUser, 3, { 2,1,13 } },
138
139 };
140
141 oid usmUser_variables_oid[] = {1,3,6,1,6,3,15,1,2};
142
143
144 /* needed for the write_ functions to find the start of the index */
145 #define USM_MIB_LENGTH 12
146
147 static unsigned int usmUserSpinLock=0;
148
149 void
150 init_usmUser(void)
151 {
152   snmpd_register_config_handler("usmUser",
153                                 usm_parse_config_usmUser, NULL, NULL);
154   snmpd_register_config_handler("createUser",
155                                 usm_parse_create_usmUser, NULL,
156                                 "username (MD5|SHA) passphrase [DES] [passphrase]");
157
158   /* we need to be called back later */
159   snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
160                          usm_store_users, NULL);
161   
162   REGISTER_MIB("snmpv3/usmUser", usmUser_variables, variable4,
163                                  usmUser_variables_oid);
164
165 }
166
167 /*******************************************************************-o-******
168  * usm_generate_OID
169  *
170  * Parameters:
171  *      *prefix         (I) OID prefix to the usmUser table entry.
172  *       prefixLen      (I)
173  *      *uptr           (I) Pointer to a user in the user list.
174  *      *length         (O) Length of generated index OID.
175  *      
176  * Returns:
177  *      Pointer to the OID index for the user (uptr)  -OR-
178  *      NULL on failure.
179  *
180  *
181  * Generate the index OID for a given usmUser name.  'length' is set to
182  * the length of the index OID.
183  *
184  * Index OID format is:
185  *
186  *    <...prefix>.<engineID_length>.<engineID>.<user_name_length>.<user_name>
187  */
188 oid *
189 usm_generate_OID(oid *prefix, size_t prefixLen, struct usmUser *uptr,
190                        size_t *length)
191 {
192   oid *indexOid;
193   int i;
194
195   *length = 2 + uptr->engineIDLen + strlen(uptr->name) + prefixLen;
196   indexOid = (oid *) malloc(*length * sizeof(oid));
197   if (indexOid) {
198     memmove(indexOid, prefix, prefixLen * sizeof (oid));
199
200     indexOid[prefixLen] = uptr->engineIDLen;
201     for(i = 0; i < (int)uptr->engineIDLen; i++)
202       indexOid[prefixLen+1+i] = (oid) uptr->engineID[i];
203
204     indexOid[prefixLen + uptr->engineIDLen + 1] = strlen(uptr->name);
205     for(i = 0; i < (int)strlen(uptr->name); i++)
206       indexOid[prefixLen + uptr->engineIDLen + 2 + i] = (oid) uptr->name[i];
207   }
208   return indexOid;
209
210 }  /* end usm_generate_OID() */
211
212 /* usm_parse_oid(): parses an index to the usmTable to break it down into
213    a engineID component and a name component.  The results are stored in:
214
215    **engineID:   a newly malloced string.
216    *engineIDLen: The length of the malloced engineID string above.
217    **name:       a newly malloced string.
218    *nameLen:     The length of the malloced name string above.
219
220    returns 1 if an error is encountered, or 0 if successful.
221 */
222 int 
223 usm_parse_oid(oid *oidIndex, size_t oidLen,
224               unsigned char **engineID, size_t *engineIDLen,
225               unsigned char **name, size_t *nameLen)
226 {
227   int nameL;
228   int engineIDL;
229   int i;
230
231   /* first check the validity of the oid */
232   if ((oidLen <= 0) || (!oidIndex)) {
233     DEBUGMSGTL(("usmUser","parse_oid: null oid or zero length oid passed in\n"));
234     return 1;
235   }
236   engineIDL = *oidIndex;                /* initial engineID length */
237   if ((int)oidLen < engineIDL + 2) {
238     DEBUGMSGTL(("usmUser","parse_oid: invalid oid length: less than the engineIDLen\n"));
239     return 1;
240   }
241   nameL = oidIndex[engineIDL+1];        /* the initial name length */
242   if ((int)oidLen != engineIDL + nameL + 2) {
243     DEBUGMSGTL(("usmUser","parse_oid: invalid oid length: length is not exact\n"));
244     return 1;
245   }
246
247   /* its valid, malloc the space and store the results */
248   if (engineID == NULL || name == NULL) {
249     DEBUGMSGTL(("usmUser","parse_oid: null storage pointer passed in.\n"));
250     return 1;
251   }
252
253   *engineID = (unsigned char *) malloc(engineIDL);
254   if (*engineID == NULL) {
255     DEBUGMSGTL(("usmUser","parse_oid: malloc of the engineID failed\n"));
256     return 1;
257   }
258   *engineIDLen = engineIDL;
259
260   *name = (unsigned char *) malloc(nameL+1);
261   if (*name == NULL) {
262     DEBUGMSGTL(("usmUser","parse_oid: malloc of the name failed\n"));
263     free(*engineID);
264     return 1;
265   }
266   *nameLen = nameL;
267   
268   for(i = 0; i < engineIDL; i++) {
269     if (oidIndex[i+1] > 255) {
270       goto UPO_parse_error;
271     }
272     engineID[0][i] = (unsigned char) oidIndex[i+1];
273   }
274
275   for(i = 0; i < nameL; i++) {
276     if (oidIndex[i+2+engineIDL] > 255) {
277       UPO_parse_error:
278       free(*engineID);
279       free(*name);
280       return 1;
281     }
282     name[0][i] = (unsigned char) oidIndex[i+2+engineIDL];
283   }
284   name[0][nameL] = 0;
285
286   return 0;
287
288 }  /* end usm_parse_oid() */
289
290 /*******************************************************************-o-******
291  * usm_parse_user
292  *
293  * Parameters:
294  *      *name           Complete OID indexing a given usmUser entry.
295  *       name_length
296  *      
297  * Returns:
298  *      Pointer to a usmUser  -OR-
299  *      NULL if name does not convert to a usmUser.
300  * 
301  * Convert an (full) OID and return a pointer to a matching user in the
302  * user list if one exists.
303  */
304 struct usmUser *
305 usm_parse_user(oid *name, size_t name_len)
306 {
307   struct usmUser *uptr;
308
309   char *newName;
310   u_char *engineID;
311   size_t nameLen, engineIDLen;
312   
313   /* get the name and engineID out of the incoming oid */
314   if (usm_parse_oid(&name[USM_MIB_LENGTH], name_len-USM_MIB_LENGTH,
315                     &engineID, &engineIDLen, (u_char **)&newName, &nameLen))
316     return NULL;
317
318   /* Now see if a user exists with these index values */
319   uptr = usm_get_user(engineID, engineIDLen, newName);
320   free(engineID);
321   free(newName);
322
323   return uptr;
324
325 }  /* end usm_parse_user() */
326
327 /*******************************************************************-o-******
328  * var_usmUser
329  *
330  * Parameters:
331  *        *vp      (I)     Variable-binding associated with this action.
332  *        *name    (I/O)   Input name requested, output name found.
333  *        *length  (I/O)   Length of input and output oid's.
334  *         exact   (I)     TRUE if an exact match was requested.
335  *        *var_len (O)     Length of variable or 0 if function returned.
336  *      (**write_method)   Hook to name a write method (UNUSED).
337  *      
338  * Returns:
339  *      Pointer to (char *) containing related data of length 'length'
340  *        (May be NULL.)
341  *
342  *
343  * Call-back function passed to the agent in order to return information
344  * for the USM MIB tree.
345  *
346  *
347  * If this invocation is not for USMUSERSPINLOCK, lookup user name
348  * in the usmUser list.
349  *
350  * If the name does not match any user and the request
351  * is for an exact match, -or- if the usmUser list is empty, create a 
352  * new list entry.
353  *
354  * Finally, service the given USMUSER* var-bind.  A NULL user generally
355  * results in a NULL return value.
356  */
357 u_char *
358 var_usmUser(
359     struct variable *vp,
360     oid     *name,
361     size_t  *length,
362     int     exact,
363     size_t  *var_len,
364     WriteMethod **write_method)
365 {
366   struct usmUser *uptr=NULL, *nptr, *pptr;
367   int i, rtest, result;
368   oid *indexOid;
369   size_t len;
370
371   /* variables we may use later */
372   static long long_ret;
373   static u_char string[1];
374   static oid objid[2];                      /* for .0.0 */
375
376   *write_method = 0;           /* assume it isnt writable for the time being */
377   *var_len = sizeof(long_ret); /* assume an integer and change later if not */
378
379   if (vp->magic != USMUSERSPINLOCK) {
380     oid newname[MAX_OID_LEN];
381     len = (*length < vp->namelen) ? *length : vp->namelen;
382     rtest = snmp_oid_compare(name, len, vp->name, len);
383     if (rtest > 0 ||
384 /*      (rtest == 0 && !exact && (int) vp->namelen+1 < (int) *length) || */
385         (exact == 1 && rtest != 0)) {
386       if (var_len)
387         *var_len = 0;
388       return 0;
389     }
390     memset(newname, 0, sizeof(newname));
391     if (((int) *length) <= (int) vp->namelen || rtest == -1) {
392       /* oid is not within our range yet */
393       /* need to fail if not exact */
394       uptr = usm_get_userList();
395
396     } else {
397       for(nptr = usm_get_userList(), pptr = NULL, uptr = NULL; nptr != NULL;
398           pptr = nptr, nptr = nptr->next) {
399         indexOid = usm_generate_OID(vp->name, vp->namelen, nptr, &len);
400         result = snmp_oid_compare(name, *length, indexOid, len);
401         DEBUGMSGTL(("usmUser", "Checking user: %s - ", nptr->name));
402         for(i = 0; i < (int)nptr->engineIDLen; i++) {
403           DEBUGMSG(("usmUser", " %x",nptr->engineID[i]));
404         }
405         DEBUGMSG(("usmUser"," - %d \n  -> OID: ", result));
406         DEBUGMSGOID(("usmUser", indexOid, len));
407         DEBUGMSG(("usmUser","\n"));
408
409         free(indexOid);
410
411         if (exact) {
412           if (result == 0) {
413             uptr = nptr;
414           }
415         } else {
416           if (result == 0) {
417             /* found an exact match.  Need the next one for !exact */
418             uptr = nptr->next;
419           } else if (result == 1) {
420             uptr = nptr;
421           }
422         }
423       }
424     }  /* endif -- name <= vp->name */
425
426     /* if uptr is NULL and exact we need to continue for creates */
427     if (uptr == NULL && !exact)
428       return(NULL);
429
430     if (uptr) {
431       indexOid = usm_generate_OID(vp->name, vp->namelen, uptr, &len);
432       *length = len;
433       memmove(name, indexOid, len*sizeof(oid));
434       DEBUGMSGTL(("usmUser", "Found user: %s - ", uptr->name));
435       for(i = 0; i < (int)uptr->engineIDLen; i++) {
436         DEBUGMSG(("usmUser", " %x",uptr->engineID[i]));
437       }
438       DEBUGMSG(("usmUser","\n  -> OID: "));
439       DEBUGMSGOID(("usmUser", indexOid, len));
440       DEBUGMSG(("usmUser","\n"));
441
442       free(indexOid);
443     }
444   } else {
445     if (header_generic(vp,name,length,exact,var_len,write_method))
446       return 0;
447   }  /* endif -- vp->magic != USMUSERSPINLOCK */
448
449   switch(vp->magic) {
450     case USMUSERSPINLOCK:
451       *write_method = write_usmUserSpinLock;
452       long_ret = usmUserSpinLock;
453       return (unsigned char *) &long_ret;
454
455     case USMUSERSECURITYNAME:
456       if (uptr) {
457         *var_len = strlen(uptr->secName);
458         return (unsigned char *) uptr->secName;
459       }
460       return NULL;
461
462     case USMUSERCLONEFROM:
463       *write_method = write_usmUserCloneFrom;
464       if (uptr) {
465         objid[0] = 0; /* "When this object is read, the ZeroDotZero OID */
466         objid[1] = 0; /*  is returned." */
467         *var_len = sizeof(oid)*2;
468         return (unsigned char *) objid;
469       }
470       return NULL;
471
472     case USMUSERAUTHPROTOCOL:
473       *write_method = write_usmUserAuthProtocol;
474       if (uptr) {
475         *var_len = uptr->authProtocolLen*sizeof(oid);
476         return (u_char *)uptr->authProtocol;
477       }
478       return NULL;
479
480     case USMUSERAUTHKEYCHANGE:
481     case USMUSEROWNAUTHKEYCHANGE:
482
483       /* we treat these the same, and let the calling module
484          distinguish between them */
485       *write_method = write_usmUserAuthKeyChange;
486       if (uptr) {
487         *string = 0; /* always return a NULL string */
488         *var_len = 0;
489         return string;
490       }
491       return NULL;
492
493     case USMUSERPRIVPROTOCOL:
494       *write_method = write_usmUserPrivProtocol;
495       if (uptr) {
496         *var_len = uptr->privProtocolLen*sizeof(oid);
497         return (u_char *)uptr->privProtocol;
498       }
499       return NULL;
500
501     case USMUSERPRIVKEYCHANGE:
502     case USMUSEROWNPRIVKEYCHANGE:
503       /* we treat these the same, and let the calling module
504          distinguish between them */
505       *write_method = write_usmUserPrivKeyChange;
506       if (uptr) {
507         *string = 0; /* always return a NULL string */
508         *var_len = 0;
509         return string;
510       }
511       return NULL;
512
513     case USMUSERPUBLIC:
514       *write_method = write_usmUserPublic;
515       if (uptr) {
516         if (uptr->userPublicString) {
517           *var_len = strlen((char *)uptr->userPublicString);
518           return uptr->userPublicString;
519         }
520         *string = 0;
521         *var_len = 0; /* return an empty string if the public
522                                       string hasn't been defined yet */
523         return string;
524       }
525       return NULL;
526
527     case USMUSERSTORAGETYPE:
528       *write_method = write_usmUserStorageType;
529       if (uptr) {
530         long_ret = uptr->userStorageType;
531         return (unsigned char *) &long_ret;
532       }
533       return NULL;
534
535     case USMUSERSTATUS:
536       *write_method = write_usmUserStatus;
537       if (uptr) {
538         long_ret = uptr->userStatus;
539         return (unsigned char *) &long_ret;
540       }
541       return NULL;
542
543     default:
544       DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_usmUser\n", vp->magic));
545   }
546   return 0;
547
548 }  /* end var_usmUser() */
549
550 /* write_usmUserSpinLock(): called when a set is performed on the
551    usmUserSpinLock object */
552 int
553 write_usmUserSpinLock(
554    int      action,
555    u_char   *var_val,
556    u_char   var_val_type,
557    size_t   var_val_len,
558    u_char   *statP,
559    oid      *name,
560    size_t   name_len)
561 {
562   /* variables we may use later */
563   static long long_ret;
564
565   if (var_val_type != ASN_INTEGER){
566       DEBUGMSGTL(("usmUser","write to usmUserSpinLock not ASN_INTEGER\n"));
567       return SNMP_ERR_WRONGTYPE;
568   }
569   if (var_val_len > sizeof(long_ret)){
570       DEBUGMSGTL(("usmUser","write to usmUserSpinLock: bad length\n"));
571       return SNMP_ERR_WRONGLENGTH;
572   }
573   long_ret = *((long *) var_val);
574
575   if (long_ret != (long)usmUserSpinLock)
576     return SNMP_ERR_INCONSISTENTVALUE;
577
578   if (action == COMMIT) {
579     if (usmUserSpinLock == 2147483647) {
580       usmUserSpinLock = 0;
581     } else {
582       usmUserSpinLock++;
583     }
584   }
585   return SNMP_ERR_NOERROR;
586 }  /* end write_usmUserSpinLock() */
587
588 /*******************************************************************-o-******
589  * write_usmUserCloneFrom
590  *
591  * Parameters:
592  *       action
593  *      *var_val
594  *       var_val_type
595  *       var_val_len
596  *      *statP          (UNUSED)
597  *      *name           OID of user to clone from.
598  *       name_len
599  *      
600  * Returns:
601  *      SNMP_ERR_NOERROR                On success  -OR-  If user exists
602  *                                        and has already been cloned.
603  *      SNMP_ERR_GENERR                 Local function call failures.
604  *      SNMP_ERR_INCONSISTENTNAME       'name' does not exist in user list
605  *                                        -OR-  user to clone from != RS_ACTIVE.
606  *      SNMP_ERR_WRONGLENGTH            OID length > than local buffer size.
607  *      SNMP_ERR_WRONGTYPE              ASN_OBJECT_ID is wrong.
608  *
609  *
610  * XXX:  should handle action=UNDO's.
611  */
612 int
613 write_usmUserCloneFrom(
614    int      action,
615    u_char   *var_val,
616    u_char   var_val_type,
617    size_t   var_val_len,
618    u_char   *statP,
619    oid      *name,
620    size_t   name_len)
621 {
622   /* variables we may use later */
623   static oid objid[USM_LENGTH_OID_MAX], *oidptr;
624   struct usmUser *uptr, *cloneFrom;
625   size_t size;
626   
627   if (var_val_type != ASN_OBJECT_ID){
628       DEBUGMSGTL(("usmUser","write to usmUserCloneFrom not ASN_OBJECT_ID\n"));
629       return SNMP_ERR_WRONGTYPE;
630   }
631   if (var_val_len > sizeof(objid)){
632       DEBUGMSGTL(("usmUser","write to usmUserCloneFrom: bad length\n"));
633       return SNMP_ERR_WRONGLENGTH;
634   }
635   if (action == COMMIT){
636     /* parse the clonefrom objid */
637     size = var_val_len/sizeof(oid);
638     memcpy(objid, var_val, var_val_len);
639
640     if ((uptr = usm_parse_user(name, name_len)) == NULL) 
641       /* We don't allow creations here */
642       return SNMP_ERR_INCONSISTENTNAME;
643
644     /* have the user already been cloned?  If so, second cloning is
645        not allowed, but does not generate an error */
646     if (uptr->cloneFrom)
647       return SNMP_ERR_NOERROR;
648
649     /* does the cloneFrom user exist? */
650     if ((cloneFrom = usm_parse_user(objid, size)) == NULL)
651       /* We don't allow creations here */
652       return SNMP_ERR_INCONSISTENTNAME;
653
654     /* is it active */
655     if (cloneFrom->userStatus != RS_ACTIVE)
656       return SNMP_ERR_INCONSISTENTNAME;
657
658     /* set the cloneFrom OID */
659     if ((oidptr = snmp_duplicate_objid(objid, size/sizeof(oid))) == NULL)
660       return SNMP_ERR_GENERR;
661
662     /* do the actual cloning */
663
664     if (uptr->cloneFrom)
665       free(uptr->cloneFrom);
666     uptr->cloneFrom = oidptr;
667
668     usm_cloneFrom_user(cloneFrom, uptr);
669     
670   }  /* endif: action == COMMIT */
671
672   return SNMP_ERR_NOERROR;
673
674
675 }  /* end write_usmUserCloneFrom() */
676
677 /*******************************************************************-o-******
678  * write_usmUserAuthProtocol
679  *
680  * Parameters:
681  *       action
682  *      *var_val        OID of auth transform to set.
683  *       var_val_type
684  *       var_val_len
685  *      *statP
686  *      *name           OID of user upon which to perform set operation.
687  *       name_len
688  *      
689  * Returns:
690  *      SNMP_ERR_NOERROR                On success.
691  *      SNMP_ERR_GENERR
692  *      SNMP_ERR_INCONSISTENTVALUE
693  *      SNMP_ERR_NOSUCHNAME
694  *      SNMP_ERR_WRONGLENGTH
695  *      SNMP_ERR_WRONGTYPE
696  */
697 int
698 write_usmUserAuthProtocol(
699    int      action,
700    u_char   *var_val,
701    u_char   var_val_type,
702    size_t   var_val_len,
703    u_char   *statP,
704    oid      *name,
705    size_t   name_len)
706 {
707   /* variables we may use later */
708   static oid objid[USM_LENGTH_OID_MAX];
709   static oid *optr;
710   struct usmUser *uptr;
711   size_t size;
712
713   if (var_val_type != ASN_OBJECT_ID){
714       DEBUGMSGTL(("usmUser","write to usmUserAuthProtocol not ASN_OBJECT_ID\n"));
715       return SNMP_ERR_WRONGTYPE;
716   }
717   if (var_val_len > sizeof(objid)){
718       DEBUGMSGTL(("usmUser","write to usmUserAuthProtocol: bad length\n"));
719       return SNMP_ERR_WRONGLENGTH;
720   }
721   if (action == COMMIT){
722       size = var_val_len/sizeof(oid);
723       memcpy(objid, var_val, var_val_len);
724
725       /* don't allow creations here */
726       if ((uptr = usm_parse_user(name, name_len)) == NULL)
727         return SNMP_ERR_NOSUCHNAME;
728
729       /* check the objid for validity */
730       /* only allow sets to perform a change to usmNoAuthProtocol */
731       if (snmp_oid_compare(objid, size, usmNoAuthProtocol,
732                   sizeof(usmNoAuthProtocol)/sizeof(oid)) != 0)
733         return SNMP_ERR_INCONSISTENTVALUE;
734       
735       /* if the priv protocol is not usmNoPrivProtocol, we can't change */
736       if (snmp_oid_compare(uptr->privProtocol, uptr->privProtocolLen, usmNoPrivProtocol,
737                   sizeof(usmNoPrivProtocol)/sizeof(oid)) != 0)
738         return SNMP_ERR_INCONSISTENTVALUE;
739
740       /* finally, we can do it */
741       optr = uptr->authProtocol;
742       if ((uptr->authProtocol = snmp_duplicate_objid(objid, size))
743           == NULL) {
744         uptr->authProtocol = optr;
745         return SNMP_ERR_GENERR;
746       }
747       free(optr);
748       uptr->authProtocolLen = size;
749   }
750   return SNMP_ERR_NOERROR;
751 }  /* end write_usmUserAuthProtocol() */
752
753 /*******************************************************************-o-******
754  * write_usmUserAuthKeyChange
755  *
756  * Parameters:
757  *       action         
758  *      *var_val        Octet string representing new KeyChange value.
759  *       var_val_type
760  *       var_val_len
761  *      *statP          (UNUSED)
762  *      *name           OID of user upon which to perform set operation.
763  *       name_len
764  *      
765  * Returns:
766  *      SNMP_ERR_NOERR          Success.
767  *      SNMP_ERR_WRONGTYPE      
768  *      SNMP_ERR_WRONGLENGTH    
769  *      SNMP_ERR_NOSUCHNAME     
770  *      SNMP_ERR_GENERR
771  *
772  * Note: This function handles both the usmUserAuthKeyChange and
773  *       usmUserOwnAuthKeyChange objects.  We are not passed the name
774  *       of the user requseting the keychange, so we leave this to the
775  *       calling module to verify when and if we should be called.  To
776  *       change this would require a change in the mib module API to
777  *       pass in the securityName requesting the change.
778  *
779  * XXX:  should handle action=UNDO's.
780  */
781 int
782 write_usmUserAuthKeyChange(
783    int      action,
784    u_char   *var_val,
785    u_char   var_val_type,
786    size_t   var_val_len,
787    u_char   *statP,
788    oid      *name,
789    size_t   name_len)
790 {
791     static unsigned char   string[SNMP_MAXBUF_SMALL];
792   struct usmUser        *uptr;
793   unsigned char          buf[SNMP_MAXBUF_SMALL];
794   size_t                 buflen = SNMP_MAXBUF_SMALL;
795
796   char                  fnAuthKey[]    = "write_usmUserAuthKeyChange",
797                         fnOwnAuthKey[] = "write_usmUserOwnAuthKeyChange",
798                         *fname;
799   
800   if (name[USM_MIB_LENGTH-1] == 6)
801     fname = fnAuthKey;
802   else
803     fname = fnOwnAuthKey;
804   
805   if (var_val_type != ASN_OCTET_STR) {
806     DEBUGMSGTL(("usmUser","write to %s not ASN_OCTET_STR\n", fname));
807     return SNMP_ERR_WRONGTYPE;
808   }
809
810   if (var_val_len > sizeof(string)) {
811     DEBUGMSGTL(("usmUser","write to %s: bad length\n", fname));
812     return SNMP_ERR_WRONGLENGTH;
813   }
814
815   if (action == COMMIT) {
816     /* don't allow creations here */
817     if ((uptr = usm_parse_user(name, name_len)) == NULL) {
818       return SNMP_ERR_NOSUCHNAME;
819     }
820
821     /* Change the key. */
822     DEBUGMSGTL(("usmUser","%s: changing auth key for user %s\n", fname, uptr->secName));
823
824     if (decode_keychange(uptr->authProtocol, uptr->authProtocolLen,
825                          uptr->authKey, uptr->authKeyLen,
826                          var_val, var_val_len,
827                          buf, &buflen) != SNMPERR_SUCCESS) {
828       DEBUGMSGTL(("usmUser","%s: ... failed\n", fname));
829         return SNMP_ERR_GENERR;
830     }
831     DEBUGMSGTL(("usmUser","%s: ... succeeded\n", fname));
832     SNMP_FREE(uptr->authKey);
833     memdup(&uptr->authKey, buf, buflen);
834     uptr->authKeyLen = buflen;
835   }
836
837   return SNMP_ERR_NOERROR;
838 } /* end write_usmUserAuthKeyChange() */
839
840 int
841 write_usmUserPrivProtocol(
842    int      action,
843    u_char   *var_val,
844    u_char   var_val_type,
845    size_t   var_val_len,
846    u_char   *statP,
847    oid      *name,
848    size_t   name_len)
849 {
850   /* variables we may use later */
851   static oid objid[USM_LENGTH_OID_MAX];
852   static oid *optr;
853   struct usmUser *uptr;
854   size_t size;
855
856   if (var_val_type != ASN_OBJECT_ID){
857       DEBUGMSGTL(("usmUser","write to usmUserPrivProtocol not ASN_OBJECT_ID\n"));
858       return SNMP_ERR_WRONGTYPE;
859   }
860   if (var_val_len > sizeof(objid)){
861       DEBUGMSGTL(("usmUser","write to usmUserPrivProtocol: bad length\n"));
862       return SNMP_ERR_WRONGLENGTH;
863   }
864   if (action == COMMIT){
865       size = var_val_len/sizeof(oid);
866       memcpy(objid, var_val, var_val_len);
867
868       /* don't allow creations here */
869       if ((uptr = usm_parse_user(name, name_len)) == NULL)
870         return SNMP_ERR_NOSUCHNAME;
871
872       /* check the objid for validity */
873       /* only allow sets to perform a change to usmNoPrivProtocol */
874       if (snmp_oid_compare(objid, size, usmNoPrivProtocol,
875                   sizeof(usmNoPrivProtocol)/sizeof(oid)) != 0)
876         return SNMP_ERR_INCONSISTENTVALUE;
877       
878       /* finally, we can do it */
879       optr = uptr->privProtocol;
880       if ((uptr->privProtocol = snmp_duplicate_objid(objid, size))
881           == NULL) {
882         uptr->privProtocol = optr;
883         return SNMP_ERR_GENERR;
884       }
885       free(optr);
886       uptr->privProtocolLen = size;
887   }
888   return SNMP_ERR_NOERROR;
889 }  /* end write_usmUserPrivProtocol() */
890
891 /*
892  * Note: This function handles both the usmUserPrivKeyChange and
893  *       usmUserOwnPrivKeyChange objects.  We are not passed the name
894  *       of the user requseting the keychange, so we leave this to the
895  *       calling module to verify when and if we should be called.  To
896  *       change this would require a change in the mib module API to
897  *       pass in the securityName requesting the change.
898  *
899  */
900 int
901 write_usmUserPrivKeyChange(
902    int      action,
903    u_char   *var_val,
904    u_char   var_val_type,
905    size_t   var_val_len,
906    u_char   *statP,
907    oid      *name,
908    size_t   name_len)
909 {
910   static unsigned char   string[SNMP_MAXBUF_SMALL];
911   struct usmUser        *uptr;
912   unsigned char          buf[SNMP_MAXBUF_SMALL];
913   size_t                 buflen = SNMP_MAXBUF_SMALL;
914
915   char                  fnPrivKey[]    = "write_usmUserPrivKeyChange",
916                         fnOwnPrivKey[] = "write_usmUserOwnPrivKeyChange",
917                         *fname;
918   
919   if (name[USM_MIB_LENGTH-1] == 9)
920     fname = fnPrivKey;
921   else
922     fname = fnOwnPrivKey;
923   
924   if (var_val_type != ASN_OCTET_STR) {
925     DEBUGMSGTL(("usmUser","write to %s not ASN_OCTET_STR\n", fname));
926     return SNMP_ERR_WRONGTYPE;
927   }
928
929   if (var_val_len > sizeof(string)) {
930     DEBUGMSGTL(("usmUser","write to %s: bad length\n", fname));
931     return SNMP_ERR_WRONGLENGTH;
932   }
933
934   if (action == COMMIT) {
935     /* don't allow creations here */
936     if ((uptr = usm_parse_user(name, name_len)) == NULL) {
937       return SNMP_ERR_NOSUCHNAME;
938     }
939
940     /* Change the key. */
941     DEBUGMSGTL(("usmUser","%s: changing priv key for user %s\n", fname, uptr->secName));
942
943     if (decode_keychange(uptr->authProtocol, uptr->authProtocolLen,
944                          uptr->privKey, uptr->privKeyLen,
945                          var_val, var_val_len,
946                          buf, &buflen) != SNMPERR_SUCCESS) {
947       DEBUGMSGTL(("usmUser","%s: ... failed\n", fname));
948         return SNMP_ERR_GENERR;
949     }
950     DEBUGMSGTL(("usmUser","%s: ... succeeded\n", fname));
951     SNMP_FREE(uptr->privKey);
952     memdup(&uptr->privKey, buf, buflen);
953     uptr->privKeyLen = buflen;
954   }
955
956   return SNMP_ERR_NOERROR;
957 }  /* end write_usmUserPrivKeyChange() */
958
959 int
960 write_usmUserPublic(
961    int      action,
962    u_char   *var_val,
963    u_char   var_val_type,
964    size_t   var_val_len,
965    u_char   *statP,
966    oid      *name,
967    size_t   name_len)
968 {
969   /* variables we may use later */
970   static unsigned char string[SNMP_MAXBUF];
971
972   struct usmUser *uptr;
973
974   if (var_val_type != ASN_OCTET_STR){
975       DEBUGMSGTL(("usmUser","write to usmUserPublic not ASN_OCTET_STR\n"));
976       return SNMP_ERR_WRONGTYPE;
977   }
978   if (var_val_len > sizeof(string)){
979       DEBUGMSGTL(("usmUser","write to usmUserPublic: bad length\n"));
980       return SNMP_ERR_WRONGLENGTH;
981   }
982   if (action == COMMIT) {
983     /* don't allow creations here */
984     if ((uptr = usm_parse_user(name, name_len)) == NULL) {
985       return SNMP_ERR_NOSUCHNAME;
986     }
987     if (uptr->userPublicString)
988       free(uptr->userPublicString);
989     uptr->userPublicString = (u_char *) malloc(var_val_len+1);
990     if (uptr->userPublicString == NULL) {
991       return SNMP_ERR_GENERR;
992     }
993     memcpy(uptr->userPublicString, var_val, var_val_len);
994     uptr->userPublicString[var_val_len] = 0;
995     DEBUGMSG(("usmUser", "setting public string: %d - %s\n", var_val_len,
996               uptr->userPublicString));
997   }
998   return SNMP_ERR_NOERROR;
999 }  /* end write_usmUserPublic() */
1000
1001 int
1002 write_usmUserStorageType(
1003    int      action,
1004    u_char   *var_val,
1005    u_char   var_val_type,
1006    size_t   var_val_len,
1007    u_char   *statP,
1008    oid      *name,
1009    size_t   name_len)
1010 {
1011   /* variables we may use later */
1012   static long long_ret;
1013   struct usmUser *uptr;
1014   
1015   if (var_val_type != ASN_INTEGER){
1016       DEBUGMSGTL(("usmUser","write to usmUserStorageType not ASN_INTEGER\n"));
1017       return SNMP_ERR_WRONGTYPE;
1018   }
1019   if (var_val_len > sizeof(long_ret)){
1020       DEBUGMSGTL(("usmUser","write to usmUserStorageType: bad length\n"));
1021       return SNMP_ERR_WRONGLENGTH;
1022   }
1023   if (action == COMMIT){
1024       /* don't allow creations here */
1025       if ((uptr = usm_parse_user(name, name_len)) == NULL) {
1026         return SNMP_ERR_NOSUCHNAME;
1027       }
1028       long_ret = *((long *) var_val);
1029       if ((long_ret == ST_VOLATILE || long_ret == ST_NONVOLATILE) &&
1030           (uptr->userStorageType == ST_VOLATILE ||
1031            uptr->userStorageType == ST_NONVOLATILE))
1032         uptr->userStorageType = long_ret;
1033       else
1034         return SNMP_ERR_INCONSISTENTVALUE;
1035   }
1036   return SNMP_ERR_NOERROR;
1037 }  /* end write_usmUserStorageType() */
1038
1039 /*******************************************************************-o-******
1040  * write_usmUserStatus
1041  *
1042  * Parameters:
1043  *       action
1044  *      *var_val
1045  *       var_val_type
1046  *       var_val_len
1047  *      *statP
1048  *      *name
1049  *       name_len
1050  *      
1051  * Returns:
1052  *      SNMP_ERR_NOERROR                On success.
1053  *      SNMP_ERR_GENERR 
1054  *      SNMP_ERR_INCONSISTENTNAME
1055  *      SNMP_ERR_INCONSISTENTVALUE
1056  *      SNMP_ERR_WRONGLENGTH
1057  *      SNMP_ERR_WRONGTYPE
1058  */
1059 int
1060 write_usmUserStatus(
1061    int      action,
1062    u_char   *var_val,
1063    u_char   var_val_type,
1064    size_t   var_val_len,
1065    u_char   *statP,
1066    oid      *name,
1067    size_t   name_len)
1068 {
1069   /* variables we may use later */
1070   static long long_ret;
1071   unsigned char *engineID;
1072   size_t engineIDLen;
1073   char *newName;
1074   size_t nameLen;
1075   struct usmUser *uptr;
1076   
1077   if (var_val_type != ASN_INTEGER){
1078       DEBUGMSGTL(("usmUser","write to usmUserStatus not ASN_INTEGER\n"));
1079       return SNMP_ERR_WRONGTYPE;
1080   }
1081   if (var_val_len > sizeof(long_ret)){
1082       DEBUGMSGTL(("usmUser","write to usmUserStatus: bad length\n"));
1083       return SNMP_ERR_WRONGLENGTH;
1084   }
1085   if (action == COMMIT){
1086     long_ret = *((long *) var_val);
1087
1088     /* ditch illegal values now */
1089     /* notReady can not be used, but the return error code is not mentioned */
1090     if (long_ret == RS_NOTREADY || long_ret < 1 || long_ret > 6)
1091       return SNMP_ERR_INCONSISTENTVALUE;
1092     
1093     /* see if we can parse the oid for engineID/name first */
1094     if (usm_parse_oid(&name[USM_MIB_LENGTH], name_len-USM_MIB_LENGTH,
1095                       &engineID, &engineIDLen, (u_char **)&newName, &nameLen))
1096       return SNMP_ERR_INCONSISTENTNAME;
1097
1098     /* Now see if a user already exists with these index values */
1099     uptr = usm_get_user(engineID, engineIDLen, newName);
1100
1101
1102     if (uptr) {                 /* If so, we set the appropriate value... */
1103       free(engineID);
1104       free(newName);
1105       if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) {
1106         return SNMP_ERR_INCONSISTENTVALUE;
1107       }
1108       if (long_ret == RS_DESTROY) {
1109         usm_remove_user(uptr);
1110         usm_free_user(uptr);
1111       } else {
1112         uptr->userStatus = long_ret;
1113       }
1114
1115     } else {                    /* ...else we create a new user */
1116       /* check for a valid status column set */
1117       if (long_ret == RS_ACTIVE || long_ret == RS_NOTINSERVICE) {
1118         free(engineID);
1119         free(newName);
1120         return SNMP_ERR_INCONSISTENTVALUE;
1121       }
1122       if (long_ret == RS_DESTROY) {
1123         /* destroying a non-existent row is actually legal */
1124         free(engineID);
1125         free(newName);
1126         return SNMP_ERR_NOERROR;
1127       }
1128
1129       /* generate a new user */
1130       if ((uptr = usm_create_user()) == NULL) {
1131         free(engineID);
1132         free(newName);
1133         return SNMP_ERR_GENERR;
1134       }
1135
1136       /* copy in the engineID */
1137       uptr->engineID =
1138         (unsigned char *) malloc(engineIDLen);
1139       if (uptr->engineID == NULL) {
1140         free(engineID);
1141         free(newName);
1142         usm_free_user(uptr);
1143         return SNMP_ERR_GENERR;
1144       }
1145       uptr->engineIDLen = engineIDLen;
1146       memcpy(uptr->engineID, engineID, engineIDLen);
1147       free(engineID);
1148
1149       /* copy in the name and secname */
1150       if ((uptr->name = strdup(newName)) == NULL) {
1151         free(newName);
1152         usm_free_user(uptr);
1153         return SNMP_ERR_GENERR;
1154       }
1155       free(newName);
1156       if ((uptr->secName = strdup(uptr->name)) == NULL) {
1157         usm_free_user(uptr);
1158         return SNMP_ERR_GENERR;
1159       }
1160
1161       /* set the status of the row based on the request */
1162       if (long_ret == RS_CREATEANDGO)
1163         uptr->userStatus = RS_ACTIVE;
1164       else if (long_ret == RS_CREATEANDWAIT)
1165         uptr->userStatus = RS_NOTINSERVICE;
1166
1167       /* finally, add it to our list of users */
1168       usm_add_user(uptr);
1169
1170     }  /* endif -- uptr */
1171   }  /* endif -- action==COMMIT */
1172
1173   return SNMP_ERR_NOERROR;
1174
1175 }  /* end write_usmUserStatus() */
1176
1177 #endif /* CYGPKG_SNMPAGENT_V3_SUPPORT */