2 * Copyright (C) 2002-2004 Novell, Inc.
4 * edir_ldapext.c LDAP extension for reading eDirectory universal password
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of version 2 of the GNU General Public License as published
8 * by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, contact Novell, Inc.
18 * To contact Novell about this file by physical or electronic mail, you may
19 * find current contact information at www.novell.com.
26 /* NMAS error codes */
27 #define NMAS_E_BASE (-1600)
29 #define NMAS_SUCCESS 0
30 #define NMAS_E_SUCCESS NMAS_SUCCESS /* Alias */
31 #define NMAS_OK NMAS_SUCCESS /* Alias */
33 #define NMAS_E_FRAG_FAILURE (NMAS_E_BASE-31) /* -1631 0xFFFFF9A1 */
34 #define NMAS_E_BUFFER_OVERFLOW (NMAS_E_BASE-33) /* -1633 0xFFFFF99F */
35 #define NMAS_E_SYSTEM_RESOURCES (NMAS_E_BASE-34) /* -1634 0xFFFFF99E */
36 #define NMAS_E_INSUFFICIENT_MEMORY (NMAS_E_BASE-35) /* -1635 0xFFFFF99D */
37 #define NMAS_E_NOT_SUPPORTED (NMAS_E_BASE-36) /* -1636 0xFFFFF99C */
38 #define NMAS_E_INVALID_PARAMETER (NMAS_E_BASE-43) /* -1643 0xFFFFF995 */
39 #define NMAS_E_INVALID_VERSION (NMAS_E_BASE-52) /* -1652 0xFFFFF98C */
41 /* OID of LDAP extenstion calls to read Universal Password */
42 #define NMASLDAP_GET_PASSWORD_REQUEST "2.16.840.1.113719.1.39.42.100.13"
43 #define NMASLDAP_GET_PASSWORD_RESPONSE "2.16.840.1.113719.1.39.42.100.14"
45 #define NMAS_LDAP_EXT_VERSION 1
47 /* OID of LDAP extension call to perform NMAS authentication */
48 #define RADAUTH_OID_NMAS_AUTH_REQUEST "2.16.840.1.113719.1.510.100.1"
49 #define RADAUTH_OID_NMAS_AUTH_REPLY "2.16.840.1.113719.1.510.100.2"
51 #define RADAUTH_LDAP_EXT_VERSION 1
53 #define REQUEST_CHALLENGED 1
56 /* ------------------------------------------------------------------------
57 * berEncodePasswordData
58 * ==============================
59 * RequestBer contents:
60 * clientVersion INTEGER
61 * targetObjectDN OCTET STRING
62 * password1 OCTET STRING
63 * password2 OCTET STRING
66 * This function takes the request BER value and input data items
67 * and BER encodes the data into the BER value
69 * ------------------------------------------------------------------------ */
70 int berEncodePasswordData(
71 struct berval **requestBV,
77 BerElement *requestBer = NULL;
79 char * utf8ObjPtr = NULL;
81 char * utf8PwdPtr = NULL;
83 char * utf8Pwd2Ptr = NULL;
87 utf8ObjSize = strlen(objectDN)+1;
88 utf8ObjPtr = objectDN;
92 utf8PwdSize = strlen(password)+1;
93 utf8PwdPtr = password;
96 if (password2 != NULL)
98 utf8Pwd2Size = strlen(password2)+1;
99 utf8Pwd2Ptr = password2;
102 /* Allocate a BerElement for the request parameters.*/
103 if((requestBer = ber_alloc()) == NULL)
105 err = NMAS_E_FRAG_FAILURE;
109 if (password != NULL && password2 != NULL)
111 /* BER encode the NMAS Version, the objectDN, and the password */
112 rc = ber_printf(requestBer, "{iooo}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize, utf8PwdPtr, utf8PwdSize, utf8Pwd2Ptr, utf8Pwd2Size);
114 else if (password != NULL)
116 /* BER encode the NMAS Version, the objectDN, and the password */
117 rc = ber_printf(requestBer, "{ioo}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize, utf8PwdPtr, utf8PwdSize);
121 /* BER encode the NMAS Version and the objectDN */
122 rc = ber_printf(requestBer, "{io}", NMAS_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize);
127 err = NMAS_E_FRAG_FAILURE;
136 * Convert the BER we just built to a berval that we'll send with the extended request.
138 if(ber_flatten(requestBer, requestBV) == LBER_ERROR)
140 err = NMAS_E_FRAG_FAILURE;
148 ber_free(requestBer, 1);
152 } /* End of berEncodePasswordData */
154 /* ------------------------------------------------------------------------
155 * berDecodeLoginData()
156 * ==============================
157 * ResponseBer contents:
158 * serverVersion INTEGER
163 * This function takes the reply BER Value and decodes the
164 * NMAS server version and return code and if a non null retData
165 * buffer was supplied, tries to decode the the return data and length
167 * ------------------------------------------------------------------------ */
168 int berDecodeLoginData(
169 struct berval *replyBV,
175 BerElement *replyBer = NULL;
176 char *retOctStr = NULL;
177 size_t retOctStrLen = 0;
179 if((replyBer = ber_init(replyBV)) == NULL)
181 err = NMAS_E_SYSTEM_RESOURCES;
187 retOctStrLen = *retDataLen + 1;
188 retOctStr = (char *)malloc(retOctStrLen);
191 err = NMAS_E_SYSTEM_RESOURCES;
195 if( (rc = ber_scanf(replyBer, "{iis}", serverVersion, &err, retOctStr, &retOctStrLen)) != -1)
197 if (*retDataLen >= retOctStrLen)
199 memcpy(retData, retOctStr, retOctStrLen);
203 err = NMAS_E_BUFFER_OVERFLOW;
206 *retDataLen = retOctStrLen;
210 err = NMAS_E_FRAG_FAILURE;
215 if( (rc = ber_scanf(replyBer, "{ii}", serverVersion, &err)) == -1)
219 err = NMAS_E_FRAG_FAILURE;
228 ber_free(replyBer, 1);
231 if (retOctStr != NULL)
233 memset(retOctStr, 0, retOctStrLen);
238 } /* End of berDecodeLoginData */
240 /* -----------------------------------------------------------------------
241 * nmasldap_get_password()
242 * ==============================
245 * This API attempts to get the universal password
247 * ------------------------------------------------------------------------ */
248 int nmasldap_get_password(
251 size_t *pwdSize, // in bytes
256 struct berval *requestBV = NULL;
257 char *replyOID = NULL;
258 struct berval *replyBV = NULL;
261 size_t pwdBufLen, bufferLen;
263 #ifdef NOT_N_PLAT_NLM
264 int currentThreadGroupID;
267 /* Validate char parameters. */
268 if(objectDN == NULL || (strlen(objectDN) == 0) || pwdSize == NULL || ld == NULL)
270 return NMAS_E_INVALID_PARAMETER;
273 bufferLen = pwdBufLen = *pwdSize;
274 pwdBuf = (char *)malloc(pwdBufLen+2);
277 return NMAS_E_INSUFFICIENT_MEMORY;
280 #ifdef NOT_N_PLAT_NLM
281 currentThreadGroupID = SetThreadGroupID(nmasLDAPThreadGroupID);
284 err = berEncodePasswordData(&requestBV, objectDN, NULL, NULL);
290 /* Call the ldap_extended_operation (synchronously) */
291 if((err = ldap_extended_operation_s(ld, NMASLDAP_GET_PASSWORD_REQUEST, requestBV, NULL, NULL, &replyOID, &replyBV)))
296 /* Make sure there is a return OID */
299 err = NMAS_E_NOT_SUPPORTED;
303 /* Is this what we were expecting to get back. */
304 if(strcmp(replyOID, NMASLDAP_GET_PASSWORD_RESPONSE))
306 err = NMAS_E_NOT_SUPPORTED;
310 /* Do we have a good returned berval? */
314 * No; returned berval means we experienced a rather drastic error.
315 * Return operations error.
317 err = NMAS_E_SYSTEM_RESOURCES;
321 err = berDecodeLoginData(replyBV, &serverVersion, &pwdBufLen, pwdBuf);
323 if(serverVersion != NMAS_LDAP_EXT_VERSION)
325 err = NMAS_E_INVALID_VERSION;
329 if (!err && pwdBufLen != 0)
331 if (*pwdSize >= pwdBufLen+1 && pwd != NULL)
333 memcpy(pwd, pwdBuf, pwdBufLen);
334 pwd[pwdBufLen] = 0; /* add null termination */
336 *pwdSize = pwdBufLen; /* does not include null termination */
346 /* Free the return OID string if one was returned. */
349 ldap_memfree(replyOID);
352 /* Free memory allocated while building the request ber and berval. */
355 ber_bvfree(requestBV);
360 memset(pwdBuf, 0, bufferLen);
364 #ifdef NOT_N_PLAT_NLM
365 SetThreadGroupID(currentThreadGroupID);
368 /* Return the appropriate error/success code. */
370 } /* end of nmasldap_get_password */
372 /* ------------------------------------------------------------------------
374 * ==============================
375 * RequestBer contents:
376 * targetObjectDN OCTET STRING
382 * This function takes the request BER value and input data items
383 * and BER encodes the data into the BER value
385 * ------------------------------------------------------------------------ */
386 int berEncodeAuthData(
387 struct berval **requestBV,
396 BerElement *requestBer = NULL;
398 char * utf8ObjPtr = NULL;
400 char * utf8PwdPtr = NULL;
402 char * utf8NasIPPtr = NULL;
403 int utf8NasIPSize = 0;
404 char * utf8StatePtr = NULL;
405 int utf8StateSize = 0;
406 char * utf8SeqPtr = NULL;
408 int state_present = 0;
410 utf8ObjSize = strlen(objectDN)+1;
411 utf8ObjPtr = objectDN;
413 utf8PwdSize = strlen(pwd);
416 utf8SeqSize = strlen(sequence)+1;
417 utf8SeqPtr = sequence;
419 utf8NasIPSize = strlen(NasIP)+1;
420 utf8NasIPPtr = NasIP;
422 /* Allocate a BerElement for the request parameters.*/
423 if((requestBer = ber_alloc()) == NULL)
425 err = NMAS_E_FRAG_FAILURE;
429 /* BER encode the NMAS Version, the objectDN, and the password */
430 rc = ber_printf(requestBer, "{ioooo", RADAUTH_LDAP_EXT_VERSION, utf8ObjPtr, utf8ObjSize, utf8PwdPtr, utf8PwdSize, utf8SeqPtr, utf8SeqSize, utf8NasIPPtr, utf8NasIPSize);
432 if( *auth_state == -2)
434 utf8StateSize = strlen(state)+1;
435 utf8StatePtr = state;
437 rc = ber_printf(requestBer, "io}", state_present, utf8StatePtr, utf8StateSize);
441 rc = ber_printf(requestBer, "i}", state_present);
446 err = NMAS_E_FRAG_FAILURE;
454 * Convert the BER we just built to a berval that we'll send with the extended request.
456 if(ber_flatten(requestBer, requestBV) == -1)
458 err = NMAS_E_FRAG_FAILURE;
466 ber_free(requestBer, 1);
470 } /* End of berEncodeAuthData */
472 /* ------------------------------------------------------------------------
473 * berDecodeAuthData()
474 * ==============================
475 * ResponseBer contents:
476 * serverVersion INTEGER
478 * challenge_data OCTET STRING
481 * This function takes the reply BER Value and decodes the
482 * server version and return code and if a non null retData
483 * buffer was supplied, tries to decode the the return data and length
485 * ------------------------------------------------------------------------ */
486 int berDecodeAuthData(
487 struct berval *replyBV,
494 BerElement *replyBer = NULL;
495 struct berval challenge = {0};
497 if((replyBer = ber_init(replyBV)) == NULL)
499 err = NMAS_E_SYSTEM_RESOURCES; // fix err code
502 if( (rc = ber_scanf(replyBer, "{ii", errCode, auth_state)) != -1)
504 if ( *auth_state != REQUEST_CHALLENGED )
506 if( (rc = ber_scanf(replyBer, "}")) != -1)
511 if( (rc = ber_scanf(replyBer, "o}", &challenge)) != -1)
513 if (*retDataLen >= challenge.bv_len)
515 memcpy(retData, challenge.bv_val, challenge.bv_len);
517 *retDataLen = challenge.bv_len;
525 ber_free(replyBer, 1);
529 }/* End of berDecodeLoginData */
531 /* -----------------------------------------------------------------------
532 * radLdapXtnNMASAuth()
533 * ==============================
536 * This API attempts to perform NMAS authentication.
538 * ------------------------------------------------------------------------ */
539 int radLdapXtnNMASAuth(
552 struct berval *requestBV = NULL;
553 char *replyOID = NULL;
554 struct berval *replyBV = NULL;
557 size_t challengesize;
559 challengesize = *statesize;
560 challenge = (char *)malloc(challengesize+2);
561 if(challenge == NULL)
563 return NMAS_E_INSUFFICIENT_MEMORY;
566 /* Validate char parameters. */
567 if(objectDN == NULL || (strlen(objectDN) == 0) || statesize == NULL || NasIPaddr == NULL || ld == NULL)
569 return NMAS_E_INVALID_PARAMETER;
572 err = berEncodeAuthData(&requestBV, objectDN, pwd, sequence, NasIPaddr, state, auth_state);
579 /* Call the ldap_extended_operation (synchronously) */
580 if((err = ldap_extended_operation_s(ld, RADAUTH_OID_NMAS_AUTH_REQUEST, requestBV, NULL, NULL, &replyOID, &replyBV))!=0)
584 /* Make sure there is a return OID */
587 err = NMAS_E_NOT_SUPPORTED; // change error values
591 /* Is this what we were expecting to get back. */
592 if(strcmp(replyOID, RADAUTH_OID_NMAS_AUTH_REPLY))
594 err = NMAS_E_NOT_SUPPORTED; // change return value
598 /* Do we have a good returned berval? */
602 * No; returned berval means we experienced a rather drastic error.
603 * Return operations error.
605 err = NMAS_E_SYSTEM_RESOURCES; //change return value
608 err = berDecodeAuthData(replyBV, &errCode, &challengesize, challenge, auth_state);
610 /* errCode return error in case of AUTH-REJECT */
611 if (!err && challengesize!= 0)
613 if (*statesize >= challengesize+1 && challenge != NULL)
615 memcpy(state, challenge, challengesize);
616 state[challengesize] = 0; /* add null termination */
618 *statesize = challengesize; /* does not include null termination */
622 /* Free memory allocated for challenge */
633 /* Free the return OID string if one was returned. */
636 ldap_memfree(replyOID);
639 /* Free memory allocated while building the request ber and berval. */
642 ber_bvfree(requestBV);
645 #ifdef NOT_N_PLAT_NLM
646 SetThreadGroupID(currentThreadGroupID);
649 /* Return the appropriate error/success code. */
651 }/* End of radLdapXtnNMASAuth */