/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright (c) 1998-1999 Innosoft International, Inc. All Rights Reserved.
*
* Copyright (c) 1996-1997 Critical Angle Inc. All Rights Reserved.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <md5.h>
#include "lber.h"
#include "ldap.h"
#include "ldap-int.h"
/*
* DIGEST-MD5 SASL Mechanism
*/
/* use this instead of "const unsigned char" to eliminate compiler warnings */
/* size of a digest result */
/* size of a digest hex string */
/*
* extra bytes which a client response needs in addition to size of
* server challenge */
/* erase a digest_attrs_t structure */
/*
* broken-out digest attributes (with quotes removed)
* probably not NUL terminated.
*/
typedef struct {
/*
* Make a nonce (NUL terminated)
* buf -- buffer for result
* maxlen -- max length of result
* returns final length or -1 on error
*/
static int
{
/*
* it shouldn't matter too much if two threads step on this counter
* at the same time, but mutexing it wouldn't hurt
*/
static int counter;
char *dst;
int len;
struct chal_info {
} cinfo;
long r;
static int set_rand = 0;
unsigned char *p;
int j;
int fd;
int got_random;
/* initialize challenge */
return (-1);
/* get a timestamp */
/* get some randomness */
got_random = 0;
if (fd != -1) {
}
if (!got_random) {
if (set_rand == 0) {
r ^= gethostid();
srandom(r);
set_rand = 1;
}
r = random();
}
++counter;
/* compute hex for result */
}
/* take the entire time_t, plus at least 6 bytes of MD5 output */
*dst = '\0';
}
/*
* if the string is entirely in the 8859-1 subset of UTF-8, then translate
* to 8859-1 prior to MD5
*/
static void
{
unsigned char cbuf;
}
}
/* if we found a character outside 8859-1, don't alter string */
return;
}
/* convert to 8859-1 prior to applying hash */
do {
;
}
/*
* Compute MD5( "<user>:<realm>:<pass>" )
* if supplied lengths are 0, strlen() is used
* places result in hash_pass (of size DIGEST_SIZE) and returns it.
*/
static unsigned char *
unsigned char *hash_pass)
{
if (use8859_1) {
} else {
}
if (use8859_1) {
} else {
}
return (hash_pass);
}
/*
* Compute MD5("<hash_pass>:<nonce>:<cnonce>")
* places result in hash_a1 and returns hash_a1
* note that hash_pass and hash_a1 may be the same
*/
static unsigned char *
unsigned char *hash_a1)
{
return (hash_a1);
}
/*
* calculate hash response for digest auth.
* outresp must be buffer of at least DIGEST_HEX_SIZE
* outresp and hex_int may be the same
* method may be NULL if mlen is 0
*/
static void
{
"00000000000000000000000000000000";
unsigned j;
/* compute hash of A2 and put in resp */
}
}
/* compute hex_a1 from hash_a1 */
for (j = 0; j < DIGEST_SIZE; ++j) {
}
/* compute response */
} else {
}
/* compute hex_a2 from hash_a2 */
for (j = 0; j < DIGEST_SIZE; ++j) {
}
/* generate hex output */
for (j = 0; j < DIGEST_SIZE; ++j) {
}
}
/*
* generate the client response from attributes
* either one of hash_pass and hash_a1 may be NULL
* hash_a1 is used on re-authentication and takes precedence over hash_pass
*/
static int
{
static const char prefix[] =
"username=\"%.*s\",realm=\"%.*s\",nonce=\"%.*s\",nc=%.*s,cnonce=\"";
char *scan;
int len;
/* make sure we have mandatory attributes */
return (-5);
}
return (-7);
/* initialize ncount */
/* increment ncount */
if (*scan == '9') {
*scan = 'a';
break;
} else if (*scan != 'f') {
++*scan;
break;
}
*scan = '0';
--scan;
}
}
/* sanity check length */
if (attr->charsetlen > 0) {
/* includes 1 for a comma */
}
return (-3);
/* charset */
*scan++ = ',';
}
/* generate string up to the client nonce */
/* generate client nonce */
if (len < 0)
return (len);
return (-3);
/* compute response */
return (-7);
}
/* finish it */
/* set final length */
return (0);
}
/* parse a digest auth string */
static int
{
for (;;) {
/* skip over commas */
/* parse attribute */
return (-5);
}
/* parse value */
scan += 2;
/* skip over "\" quoting, but don't remove it */
if (*scan == '\\') {
return (-5);
scan += 2;
} else {
++scan;
}
}
if (*scan != '"')
return (-5);
++scan;
} else {
++scan;
}
if (!vlen)
return (-5);
/* lookup the attribute */
switch (*attr) {
case 'c':
case 'C':
}
}
break;
case 'd':
case 'D':
}
}
break;
case 'm':
case 'M':
}
break;
case 'n':
case 'N':
}
}
break;
case 'q':
case 'Q':
}
break;
case 'r':
case 'R':
}
}
break;
case 's':
case 'S':
}
break;
case 'u':
case 'U':
}
break;
}
/* we should be at the end of the string or a comma */
if (*scan != ',')
return (-5);
}
return (0);
}
static int ldap_digest_md5_encode(
const char *challenge,
const char *username,
const char *passwd,
char **digest
)
{
char *outbuf;
int outlen;
int ret;
/* validate args */
return (LDAP_PARAM_ERROR);
}
/* parse the challenge */
if (ret != 0)
return (LDAP_DECODING_ERROR);
/* server MUST specify support for charset=utf-8 */
"server did not specify charset=utf-8\n",
0, 0, 0);
return (LDAP_NOT_SUPPORTED);
}
/* set up digest attributes */
/* allocate the output buffer */
return (LDAP_NO_MEMORY);
/* hash the password */
/* create the response */
if (ret != 0) {
return (LDAP_DECODING_ERROR);
}
/* null terminate the response */
return (LDAP_SUCCESS);
}
char *user_name,
{
int errnum;
/* Add debug */
return (LDAP_PARAM_ERROR);
return (LDAP_PARAM_ERROR);
if (errnum == LDAP_SASL_BIND_IN_PROGRESS) {
"SASL challenge: %s\n",
if (errnum == LDAP_SUCCESS) {
"SASL reply: %s\n",
digest, 0, 0);
}
} else {
}
}
return (errnum);
}
static int
char *user_name,
int *msgidp)
{
return (LDAP_PARAM_ERROR);
return (LDAP_PARAM_ERROR);
}
static int
char *user_name,
int *msgidp)
{
int errnum;
int err;
return (LDAP_PARAM_ERROR);
return (LDAP_PARAM_ERROR);
if (err != LDAP_SASL_BIND_IN_PROGRESS)
return (err);
!= LDAP_SUCCESS)
return (err);
return (LDAP_NO_MEMORY);
if (err == LDAP_SUCCESS) {
digest, 0, 0);
}
return (err);
}
char *user_name,
{
int msgid;
int rc;
return (LDAP_PARAM_ERROR);
return (LDAP_PARAM_ERROR);
if (rc != LDAP_SUCCESS)
return (rc);
if (rc == -1) {
}
if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
return (rc);
}
if (rc != LDAP_SUCCESS)
return (rc);
if (rc == -1) {
}
return (rc);
}