4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1999 by Sun Microsystems, Inc.
24 * All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This file contains all authentication-related functionality for
31 * SLP. Two interfaces are exported:
33 * slp_sign: Creates auth blocks for a given piece of data
34 * slp_verify: Verifies an auth block for a given piece of data.
36 * A shared object which provides crypto-suites and key management
37 * functionality is dynamically linked in during intialization. If
38 * the shared object cannot be found, the authentication code aborts
39 * and an SLP_AUTHENTICATION_FAILED error is returned. Which shared
40 * object is actually loaded is controlled by the property
41 * sun.net.slp.authBackend; the value of this property should contain
42 * either the name of a shared object which implements the necessary
43 * interfaces, or a full or relative path to such an object. This value
44 * will be passed to dlopen(3X) to resolve the symbols.
46 * The shared object must implement the following AMI interfaces:
55 * AMI_MD5WithRSAEncryption_AID
56 * AMI_SHA1WithDSASignature_AID
58 * See security/ami.h for more info on these interfaces.
67 #include <slp-internal.h>
70 /* Prototypes for dynamically loaded (dl'd) AMI functions */
71 static ami_algid
**ami_rsa_aid
, **ami_dsa_aid
;
72 static AMI_STATUS (*dld_ami_init
)(ami_handle_t
**, const char *,
73 const char *, const u_int
, const u_int
,
76 static AMI_STATUS (*dld_ami_sign
)(ami_handle_t
*,
86 static AMI_STATUS (*dld_ami_verify
)(ami_handle_t
*,
96 static AMI_STATUS (*dld_ami_get_cert
)(const ami_handle_t
*,
100 static AMI_STATUS (*dld_ami_get_cert_chain
)(const ami_handle_t
*,
106 static AMI_STATUS (*dld_ami_str2dn
)(const ami_handle_t
*,
107 char *, ami_name
**);
108 static AMI_STATUS (*dld_ami_dn2str
)(const ami_handle_t
*,
109 ami_name
*, char **);
110 static void (*dld_ami_free_cert_list
)(ami_cert
**, int);
111 static void (*dld_ami_free_dn
)(ami_name
**);
112 static char *(*dld_ami_strerror
)(const ami_handle_t
*, const AMI_STATUS
);
113 static AMI_STATUS (*dld_ami_end
)(ami_handle_t
*);
115 /* local utilities */
116 static SLPError
get_security_backend();
117 static SLPError
make_tbs(const char *, struct iovec
*, int,
118 unsigned int, unsigned char **, size_t *);
119 static SLPError
make_authblock(struct iovec
*, int, const char *,
120 time_t, caddr_t
*, size_t *);
121 static SLPError
do_verify(unsigned char *, size_t, unsigned short,
122 const unsigned char *, size_t, const char *);
123 static char *alias2dn(ami_handle_t
*);
124 static SLPError
check_spis(ami_handle_t
*, ami_cert
*, int, const char *);
125 static int dncmp(ami_handle_t
*, const char *, const char *);
128 * Creates a cryptographic signature over the components of authiov, and
129 * creates an auth block from the signature. The auth block is placed
130 * into msgiov at the index specified by msgiov_index. The timestamp
131 * for the auth block is given in ts. Caller must free the auth block
134 * Returns SLP_OK on success, SLP_AUTHENTICATION_FAILED on failure.
136 SLPError
slp_sign(struct iovec
*authiov
, int authiov_len
, time_t ts
,
137 struct iovec
*msgiov
, int msg_index
) {
139 char *sign_as
= NULL
;
140 char *alias
, *aliasp
;
141 SLPError err
= SLP_OK
;
142 unsigned char num_auths
= 0;
144 /* This auth block is always at least 1 byte long, for num auths */
145 msgiov
[msg_index
].iov_base
= calloc(1, 1);
146 msgiov
[msg_index
].iov_len
= 1;
148 /* if security is off, just return the empty auth block */
149 if (!slp_get_security_on() || slp_get_bypass_auth()) {
154 * Security is disabled in Solaris 8 due to AMI trouble.
155 * The pragmas and LINTED suppress "statement not reached"
156 * compiler and lint warnings, and should be removed when
157 * security is re-enabled.
159 return (SLP_SECURITY_UNAVAILABLE
);
161 #pragma error_messages(off, E_STATEMENT_NOT_REACHED)
163 /* else we should sign this advert */
164 if (!(sign_as
= (char *)SLPGetProperty(SLP_CONFIG_SIGN_AS
)) ||
165 /*LINTED statement not reached*/
168 slp_err(LOG_INFO
, 0, "slp_sign", "No signing identity given");
169 return (SLP_AUTHENTICATION_FAILED
);
172 /* Try to initialize security backend */
173 if (!(err
= get_security_backend()) == SLP_OK
) {
174 return (SLP_AUTHENTICATION_FAILED
);
177 /* dup SPI list so we can destructively modify it */
178 if (!(sign_as
= strdup(sign_as
))) {
179 slp_err(LOG_CRIT
, 0, "slp_sign", "out of memory");
180 return (SLP_MEMORY_ALLOC_FAILED
);
183 /* For each SPI, create an auth block */
184 for (aliasp
= sign_as
; aliasp
; ) {
186 aliasp
= slp_utf_strchr(aliasp
, ',');
191 /* create an auth block for this SPI */
192 err
= make_authblock(authiov
, authiov_len
, alias
, ts
,
193 &(msgiov
[msg_index
].iov_base
),
194 (size_t *)&(msgiov
[msg_index
].iov_len
));
195 if (err
== SLP_MEMORY_ALLOC_FAILED
) {
197 } else if (err
!= SLP_OK
) {
198 /* else skip and keep going */
206 if (sign_as
) free(sign_as
);
212 if (num_auths
== 0) {
213 return (SLP_AUTHENTICATION_FAILED
);
216 /* Lay in number of auth blocks created */
217 err
= slp_add_byte(msgiov
[msg_index
].iov_base
, 1, num_auths
, &off
);
221 #pragma error_messages(on, E_STATEMENT_NOT_REACHED)
225 * Verifies that the signature(s) contained in authblocks validates
226 * the data in authiov. slp_verify will not read more than len bytes
227 * from authblocks. n is the stated number of authblocks in authblock.
228 * The total length of all auth blocks read is placed in *total.
230 * Returns SLP_OK if the verification succeeds.
232 SLPError
slp_verify(struct iovec
*authiov
, int authiov_len
,
233 const char *authblocks
, size_t len
, int n
, size_t *total
) {
236 unsigned short bsd
, ablen
;
237 unsigned int timestamp
;
239 SLPError err
= SLP_AUTHENTICATION_FAILED
;
240 unsigned char *inbytes
= NULL
;
245 /* 1st: if bypass_auth == true, just return SLP_OK */
246 if (slp_get_bypass_auth()) {
250 /* 2nd: If security is off, and there are no auth blocks, OK */
251 if (!slp_get_security_on() && n
== 0) {
256 * Security is disabled in Solaris 8 due to AMI trouble.
257 * The pragmas and LINTED suppress "statement not reached"
258 * compiler and lint warnings, and should be removed when
259 * security is re-enabled.
261 return (SLP_SECURITY_UNAVAILABLE
);
262 #pragma error_messages(off, E_STATEMENT_NOT_REACHED)
264 /* For all other scenarios, we must verify the auth blocks */
265 /*LINTED statement not reached*/
266 if (get_security_backend() != SLP_OK
|| n
== 0) {
267 return (SLP_AUTHENTICATION_FAILED
);
271 * If we get here, the backend is available and there are auth
272 * blocks to verify. Verify each input auth block.
274 off
= 0; /* offset into raw auth blocks */
276 for (i
= 0; i
< n
&& off
<= len
; i
++) {
280 if ((err
= slp_get_sht(authblocks
, len
, &off
, &bsd
)) != SLP_OK
) {
281 slp_err(LOG_INFO
, 0, "slp_verify", "corrupt auth block");
285 /* Auth block length */
286 if ((err
= slp_get_sht(authblocks
, len
, &off
, &ablen
)) != SLP_OK
) {
287 slp_err(LOG_INFO
, 0, "slp_verify", "corrupt auth block");
292 if ((err
= slp_get_int32(authblocks
, len
, &off
, ×tamp
))
294 slp_err(LOG_INFO
, 0, "slp_verify", "corrupt auth block");
299 if ((err
= slp_get_string(authblocks
, len
, &off
, &spi
))
301 slp_err(LOG_INFO
, 0, "slp_verify", "corrupt auth block");
306 spi
, authiov
, authiov_len
, timestamp
, &inbytes
, &inbytes_len
);
311 sig
= (unsigned char *)(authblocks
+ off
);
312 siglen
= ablen
- (off
- this_ab
);
316 err
= do_verify(inbytes
, inbytes_len
, bsd
, sig
, siglen
, spi
);
326 if (inbytes
) free(inbytes
);
330 #pragma error_messages(on, E_STATEMENT_NOT_REACHED)
334 * When first called, attempts to dlopen a security shared library
335 * and dlsym in the necessary interfaces. The library remains mapped
336 * in, so successive calls just return SLP_OK.
338 static SLPError
get_security_backend() {
339 static mutex_t be_lock
= DEFAULTMUTEX
;
340 static void *dl
= NULL
;
341 static int got_backend
= 0;
342 SLPError err
= SLP_SECURITY_UNAVAILABLE
;
346 (void) mutex_lock(&be_lock
);
349 (void) mutex_unlock(&be_lock
);
353 if (!(libname
= SLPGetProperty(SLP_CONFIG_AUTH_BACKEND
)) ||
355 /* revert to default */
356 libname
= "libami.so.1";
359 if (!(dl
= dlopen(libname
, RTLD_LAZY
))) {
361 slp_err(LOG_INFO
, 0, "get_security_backend",
362 "Could not dlopen AMI library: %s",
363 (dlerr
? dlerr
: "unknown DL error"));
364 slp_err(LOG_INFO
, 0, "get_security_backend",
365 "Is AMI installed?");
369 /* Relocate AMI's statically initialized AIDs we need */
371 dlsym(dl
, "AMI_MD5WithRSAEncryption_AID"))) {
374 slp_err(LOG_INFO
, 0, "get_security_backend",
375 "Could not relocate AMI_MD5WithRSAEncryption_AID: %s",
376 (dlerr
? dlerr
: "unknown DL error"));
381 dlsym(dl
, "AMI_SHA1WithDSASignature_AID"))) {
384 slp_err(LOG_INFO
, 0, "get_security_backend",
385 "Could not relocate AMI_SHA1WithDSASignature_AID: %s",
386 (dlerr
? dlerr
: "unknown DL error"));
390 /* Bring in the functions we need */
391 if (!(dld_ami_init
= (AMI_STATUS (*)(ami_handle_t
**,
398 slp_err(LOG_INFO
, 0, "get_security_backend",
399 "Could not load ami_init");
403 if (!(dld_ami_sign
= (AMI_STATUS (*)(ami_handle_t
*,
414 slp_err(LOG_INFO
, 0, "get_security_backend",
415 "Could not load ami_sign");
419 if (!(dld_ami_verify
= (AMI_STATUS (*)(ami_handle_t
*,
429 dl
, "ami_verify"))) {
430 slp_err(LOG_INFO
, 0, "get_security_backend",
431 "Could not load ami_verify");
435 if (!(dld_ami_get_cert
= (AMI_STATUS (*)(const ami_handle_t
*,
439 dl
, "ami_get_cert"))) {
440 slp_err(LOG_INFO
, 0, "get_security_backend",
441 "Could not load ami_get_cert");
445 if (!(dld_ami_get_cert_chain
= (AMI_STATUS (*)(const ami_handle_t
*,
451 dl
, "ami_get_cert_chain"))) {
452 slp_err(LOG_INFO
, 0, "get_security_backend",
453 "Could not load ami_get_cert_chain");
457 if (!(dld_ami_str2dn
= (AMI_STATUS (*)(const ami_handle_t
*,
458 char *, ami_name
**))dlsym(
459 dl
, "ami_str2dn"))) {
460 slp_err(LOG_INFO
, 0, "get_security_backend",
461 "Could not load ami_str2dn");
465 if (!(dld_ami_dn2str
= (AMI_STATUS (*)(const ami_handle_t
*,
466 ami_name
*, char **))dlsym(
467 dl
, "ami_dn2str"))) {
468 slp_err(LOG_INFO
, 0, "get_security_backend",
469 "Could not load ami_dn2str");
473 if (!(dld_ami_free_cert_list
= (void (*)(ami_cert
**, int))dlsym(
474 dl
, "ami_free_cert_list"))) {
475 slp_err(LOG_INFO
, 0, "get_security_backend",
476 "Could not load ami_free_cert_list");
480 if (!(dld_ami_free_dn
= (void (*)(ami_name
**))dlsym(
481 dl
, "ami_free_dn"))) {
482 slp_err(LOG_INFO
, 0, "get_security_backend",
483 "Could not load ami_free_dn");
487 if (!(dld_ami_strerror
= (char *(*)(const ami_handle_t
*,
488 const AMI_STATUS
))dlsym(
489 dl
, "ami_strerror"))) {
490 slp_err(LOG_INFO
, 0, "get_security_backend",
491 "Could not load ami_strerror");
495 if (!(dld_ami_end
= (AMI_STATUS (*)(ami_handle_t
*))dlsym(
498 slp_err(LOG_INFO
, 0, "get_security_backend",
499 "Could not load ami_end");
507 if (!got_backend
&& dl
) {
510 (void) mutex_unlock(&be_lock
);
516 * Creates a bytes to-be-signed buffer suitable for input
517 * a signature algorithm.
519 * The only backend currently available is AMI, which does
520 * not support incremental updates for digesting. Hence we
521 * must copy all elements of the input iovec into one buffer.
523 * This function allocates a single buffer into *buf big enough
524 * to hold all necessary elements, sets *buflen to this length, and
525 * makes a bytes-to-be-signed buffer. Into this buffer is placed
526 * first the SPI string, then all elements of iov, and finally
527 * the timestamp. Caller must free *buf.
529 * Returns err != SLP_OK only on catastrophic error.
531 static SLPError
make_tbs(const char *spi
,
534 unsigned int timestamp
,
542 *buflen
= 2 + strlen(spi
);
544 for (i
= 0; i
< iovlen
; i
++) {
545 *buflen
+= iov
[i
].iov_len
;
548 *buflen
+= sizeof (timestamp
);
550 if (!(*buf
= malloc(*buflen
))) {
551 slp_err(LOG_CRIT
, 0, "slp_sign", "out of memory");
552 return (SLP_MEMORY_ALLOC_FAILED
);
555 /* @@@ ok to use caddr_t? */
558 /* Lay in SPI string */
560 if ((err
= slp_add_string(p
, *buflen
, spi
, &off
)) != SLP_OK
) {
566 /* Copy in elements of iov */
567 for (i
= 0; i
< iovlen
; i
++) {
568 (void) memcpy(p
, iov
[i
].iov_base
, iov
[i
].iov_len
);
570 off
+= iov
[i
].iov_len
;
573 /* Lay in timestamp */
574 return (slp_add_int32((char *)*buf
, *buflen
, timestamp
, &off
));
578 * Creates an auth block from the given parameters:
580 * sig_in IN Data to be signed
581 * sig_in_len IN Length of sig_in
582 * alias IN signing alias for this auth block
583 * timestamp IN Timestamp for this auth block
584 * abs IN/OUT Buffer of accumulated auth blocks
585 * abs_len IN/OUT Length of abs
587 * For each new auth block, abs is resized as necessary, and the
588 * new auth block is appended. abs_len is updated accordingly.
590 * Returns SLP_OK if the signing and auth block creation succeeded.
592 static SLPError
make_authblock(struct iovec
*authiov
, int authiov_len
,
593 const char *alias
, time_t timestamp
,
594 caddr_t
*abs
, size_t *abs_len
) {
596 unsigned char *sig_out
= NULL
;
597 size_t sig_out_len
= 0;
598 ami_handle_t
*amih
= NULL
;
601 SLPError err
= SLP_OK
;
607 unsigned char *sig_in
= NULL
;
610 /* Create the signature */
611 if ((ami_err
= dld_ami_init(&amih
, alias
, NULL
, 0, 0, NULL
))
613 slp_err(LOG_INFO
, 0, "make_authblock", "ami_init failed: %s",
614 dld_ami_strerror(amih
, ami_err
));
615 return (SLP_AUTHENTICATION_FAILED
);
618 /* determine our DN, to be used as the SPI */
619 if (!(dn
= alias2dn(amih
))) {
620 err
= SLP_AUTHENTICATION_FAILED
;
624 /* make bytes to-be-signed */
626 dn
, authiov
, authiov_len
, timestamp
, &sig_in
, &sig_in_len
);
631 /* @@@ determine the AID and BSD for this alias */
635 if ((ami_err
= dld_ami_sign(amih
, sig_in
, sig_in_len
, AMI_END_DATA
,
636 NULL
, NULL
, 0, aid
, &sig_out
, &sig_out_len
))
639 slp_err(LOG_INFO
, 0, "make_authblock", "ami_sign failed: %s",
640 dld_ami_strerror(amih
, ami_err
));
641 err
= SLP_AUTHENTICATION_FAILED
;
645 /* We can now calculate the length of the auth block */
650 2 + strlen(dn
) + /* SPI string */
651 sig_out_len
; /* the signature */
653 /* Grow buffer for already-created auth blocks, if necessary */
655 if (!(*abs
= realloc(*abs
, *abs_len
+ ab_len
))) {
656 slp_err(LOG_CRIT
, 0, "make_authblock", "out of memory");
657 err
= SLP_MEMORY_ALLOC_FAILED
;
661 ab
= *abs
+ *abs_len
;
665 err
= slp_add_sht(ab
, ab_len
, bsd
, &off
);
667 /* Auth block length */
669 err
= slp_add_sht(ab
, ab_len
, ab_len
, &off
);
674 err
= slp_add_int32(ab
, ab_len
, timestamp
, &off
);
679 err
= slp_add_string(ab
, ab_len
, dn
, &off
);
684 (void) memcpy(ab
+ off
, sig_out
, sig_out_len
);
693 if (sig_in
) free(sig_in
);
694 if (sig_out
) free(sig_out
);
696 if (err
== SLP_MEMORY_ALLOC_FAILED
) {
697 /* critical error; abort */
705 * The actual verification routine which interacts with the security
706 * backend to get a certificate for the given SPI and use that cert
707 * to verify the signature contained in the auth block.
709 * inbytes IN bytes to be verified
710 * inbytes_len IN length of inbytes
711 * bsd IN BSD for this signature
712 * sig IN the signature
713 * siglen IN length of sig
714 * spi IN SPI for this signature, not escaped
716 * Returns SLP_OK if the signature is verified, or SLP_AUTHENTICATION_FAILED
717 * if any error occured.
719 static SLPError
do_verify(unsigned char *inbytes
, size_t inbytes_len
,
720 unsigned short bsd
, const unsigned char *sig
,
721 size_t siglen
, const char *esc_spi
) {
724 ami_handle_t
*amih
= NULL
;
726 ami_cert
*certs
= NULL
;
731 /* Get the right AID */
740 slp_err(LOG_INFO
, 0, "do_verify",
741 "Unsupported BSD %d for given SPI %s", bsd
, spi
);
742 return (SLP_AUTHENTICATION_FAILED
);
745 if ((ami_err
= dld_ami_init(&amih
, spi
, NULL
, 0, 0, NULL
)) != AMI_OK
) {
746 slp_err(LOG_INFO
, 0, "do_verify", "ami_init failed: %s",
747 dld_ami_strerror(amih
, ami_err
));
748 return (SLP_AUTHENTICATION_FAILED
);
752 if ((err
= SLPUnescape(esc_spi
, &spi
, SLP_FALSE
))) {
756 /* get certificate */
757 if ((ami_err
= dld_ami_get_cert(amih
, spi
, &certs
, &ccnt
)) != AMI_OK
) {
758 slp_err(LOG_INFO
, 0, "do_verify",
759 "Can not get certificate for %s: %s",
760 spi
, dld_ami_strerror(amih
, ami_err
));
761 err
= SLP_AUTHENTICATION_FAILED
;
765 /* @@@ select the right cert, if more than one */
768 if ((ami_err
= dld_ami_verify(amih
, inbytes
, inbytes_len
, AMI_END_DATA
,
769 certs
[icert
].info
.pubKeyInfo
->algorithm
,
770 certs
[icert
].info
.pubKeyInfo
->pubKey
.value
,
771 certs
[icert
].info
.pubKeyInfo
->pubKey
.length
,
772 aid
, sig
, siglen
)) != AMI_OK
) {
774 slp_err(LOG_INFO
, 0, "do_verify", "ami_verify failed: %s",
775 dld_ami_strerror(amih
, ami_err
));
776 err
= SLP_AUTHENTICATION_FAILED
;
780 err
= check_spis(amih
, certs
, icert
, spi
);
784 dld_ami_free_cert_list(&certs
, ccnt
);
797 * Gets this process' DN, or returns NULL on failure. Caller must free
798 * the result. The reslting DN will be escaped.
800 static char *alias2dn(ami_handle_t
*amih
) {
807 if ((status
= dld_ami_get_cert(amih
, NULL
, &certs
, &ccnt
)) != AMI_OK
) {
808 slp_err(LOG_INFO
, 0, "alias2dn",
809 "Can not get my DN: %s",
810 dld_ami_strerror(amih
, status
));
815 slp_err(LOG_INFO
, 0, "alias2dn",
816 "No cert found for myself");
820 if ((status
= dld_ami_dn2str(amih
, certs
[0].info
.subject
, &answer
))
822 slp_err(LOG_INFO
, 0, "alias2dn",
823 "Can not convert DN to string: %s",
824 dld_ami_strerror(amih
, status
));
829 if (SLPEscape(answer
, &esc_answer
, SLP_FALSE
) != SLP_OK
) {
838 dld_ami_free_cert_list(&certs
, ccnt
);
843 static SLPError
check_spis(ami_handle_t
*amih
,
847 ami_cert
*chain
= NULL
;
856 /* If configured SPI == authblock SPI, we are done */
857 prop_spi
= (char *)SLPGetProperty(SLP_CONFIG_SPI
);
858 if (!prop_spi
|| !*prop_spi
) {
859 slp_err(LOG_INFO
, 0, "do_verify", "no SPI configured");
860 err
= SLP_AUTHENTICATION_FAILED
;
864 /* dup it so we can modify it */
865 if (!(prop_spi
= strdup(prop_spi
))) {
866 slp_err(LOG_CRIT
, 0, "do_verify", "out of memory");
867 err
= SLP_MEMORY_ALLOC_FAILED
;
871 /* if more than one SPI given, discard all but first */
872 if ((p
= slp_utf_strchr(prop_spi
, ','))) {
876 /* unescape configured DNs */
877 if ((err
= SLPUnescape(prop_spi
, &ue_spi
, SLP_FALSE
)) != SLP_OK
) {
883 if (dncmp(amih
, prop_spi
, spi
) == 0) {
884 /* they match, so we are done */
890 * Else we need to traverse the cert chain. ami_get_cert_chain
891 * verifies each link in the chain, so no need to do it again.
895 ami_err
= dld_ami_get_cert_chain(amih
, certs
+ icert
, cas
, 0,
897 if (ami_err
!= AMI_OK
) {
898 slp_err(LOG_INFO
, 0, "do_verify",
899 "can not get cert chain: %s",
900 dld_ami_strerror(amih
, ami_err
));
901 err
= SLP_AUTHENTICATION_FAILED
;
909 dld_ami_free_cert_list(&chain
, ccnt
);
912 if (prop_spi
) free(prop_spi
);
917 static int dncmp(ami_handle_t
*amih
, const char *s1
, const char *s2
) {
919 ami_name
*dn1
= NULL
;
920 ami_name
*dn2
= NULL
;
925 /* Normalize: convert to DN structs and back to strings */
926 if ((status
= dld_ami_str2dn(amih
, (char *)s1
, &dn1
)) != AMI_OK
) {
927 slp_err(LOG_INFO
, 0, "dncmp",
928 "can not create DN structure for %s: %s",
930 dld_ami_strerror(amih
, status
));
935 if ((status
= dld_ami_str2dn(amih
, (char *)s2
, &dn2
)) != AMI_OK
) {
936 slp_err(LOG_INFO
, 0, "dncmp",
937 "can not create DN structure for %s: %s",
939 dld_ami_strerror(amih
, status
));
944 /* convert back to strings */
945 if ((status
= dld_ami_dn2str(amih
, dn1
, &dnstr1
)) != AMI_OK
) {
946 slp_err(LOG_INFO
, 0, "dncmp",
947 "can not convert DN to string: %s",
948 dld_ami_strerror(amih
, status
));
953 if ((status
= dld_ami_dn2str(amih
, dn2
, &dnstr2
)) != AMI_OK
) {
954 slp_err(LOG_INFO
, 0, "dncmp",
955 "can not convert DN to string: %s",
956 dld_ami_strerror(amih
, status
));
961 answer
= strcasecmp(dnstr1
, dnstr2
);
965 dld_ami_free_dn(&dn1
);
969 dld_ami_free_dn(&dn2
);
972 if (dnstr1
) free(dnstr1
);
973 if (dnstr2
) free(dnstr2
);