+ if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
+ rs->sr_text = "sessionTracking control value is absent";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
+ rs->sr_text = "sessionTracking control value is empty";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ /* TODO: add the capability to determine if a client is allowed
+ * to use this control, based on identity, ip and so */
+
+ ber = ber_init( &ctrl->ldctl_value );
+ if ( ber == NULL ) {
+ rs->sr_text = "internal error";
+ return LDAP_OTHER;
+ }
+
+ tag = ber_skip_tag( ber, &len );
+ if ( tag != LBER_SEQUENCE ) {
+ tag = LBER_ERROR;
+ goto error;
+ }
+
+ /* sessionSourceIp */
+ tag = ber_peek_tag( ber, &len );
+ if ( tag == LBER_DEFAULT ) {
+ tag = LBER_ERROR;
+ goto error;
+ }
+
+ if ( len == 0 ) {
+ tag = ber_skip_tag( ber, &len );
+
+ } else if ( len > 128 ) {
+ rs->sr_text = "sessionTracking.sessionSourceIp too long";
+ rs->sr_err = LDAP_PROTOCOL_ERROR;
+ goto error;
+
+ } else {
+ tag = ber_scanf( ber, "m", &sessionSourceIp );
+ }
+
+ if ( ldif_is_not_printable( sessionSourceIp.bv_val, sessionSourceIp.bv_len ) ) {
+ BER_BVZERO( &sessionSourceIp );
+ }
+
+ /* sessionSourceName */
+ tag = ber_peek_tag( ber, &len );
+ if ( tag == LBER_DEFAULT ) {
+ tag = LBER_ERROR;
+ goto error;
+ }
+
+ if ( len == 0 ) {
+ tag = ber_skip_tag( ber, &len );
+
+ } else if ( len > 65536 ) {
+ rs->sr_text = "sessionTracking.sessionSourceName too long";
+ rs->sr_err = LDAP_PROTOCOL_ERROR;
+ goto error;
+
+ } else {
+ tag = ber_scanf( ber, "m", &sessionSourceName );
+ }
+
+ if ( ldif_is_not_printable( sessionSourceName.bv_val, sessionSourceName.bv_len ) ) {
+ BER_BVZERO( &sessionSourceName );
+ }
+
+ /* formatOID */
+ tag = ber_peek_tag( ber, &len );
+ if ( tag == LBER_DEFAULT ) {
+ tag = LBER_ERROR;
+ goto error;
+ }
+
+ if ( len == 0 ) {
+ rs->sr_text = "sessionTracking.formatOID empty";
+ rs->sr_err = LDAP_PROTOCOL_ERROR;
+ goto error;
+
+ } else if ( len > 1024 ) {
+ rs->sr_text = "sessionTracking.formatOID too long";
+ rs->sr_err = LDAP_PROTOCOL_ERROR;
+ goto error;
+
+ } else {
+ tag = ber_scanf( ber, "m", &formatOID );
+ }
+
+ rc = numericoidValidate( NULL, &formatOID );
+ if ( rc != LDAP_SUCCESS ) {
+ rs->sr_text = "sessionTracking.formatOID invalid";
+ goto error;
+ }
+
+ for ( i = 0; !BER_BVISNULL( &session_tracking_formats[ i ] ); i += 2 )
+ {
+ if ( bvmatch( &formatOID, &session_tracking_formats[ i ] ) ) {
+ formatOID = session_tracking_formats[ i + 1 ];
+ break;
+ }
+ }
+
+ /* sessionTrackingIdentifier */
+ tag = ber_peek_tag( ber, &len );
+ if ( tag == LBER_DEFAULT ) {
+ tag = LBER_ERROR;
+ goto error;
+ }
+
+ if ( len == 0 ) {
+ tag = ber_skip_tag( ber, &len );
+
+ } else {
+ /* note: should not be more than 65536... */
+ tag = ber_scanf( ber, "m", &sessionTrackingIdentifier );
+ if ( ldif_is_not_printable( sessionTrackingIdentifier.bv_val, sessionTrackingIdentifier.bv_len ) ) {
+ /* we want the OID printed, at least */
+ BER_BVSTR( &sessionTrackingIdentifier, "" );
+ }
+ }
+
+ /* closure */
+ tag = ber_skip_tag( ber, &len );
+ if ( tag != LBER_DEFAULT || len != 0 ) {
+ tag = LBER_ERROR;
+ goto error;
+ }
+ tag = 0;
+
+ st_len = 0;
+ if ( !BER_BVISNULL( &sessionSourceIp ) ) {
+ st_len += STRLENOF( "IP=" ) + sessionSourceIp.bv_len;
+ }
+ if ( !BER_BVISNULL( &sessionSourceName ) ) {
+ if ( st_len ) st_len++;
+ st_len += STRLENOF( "NAME=" ) + sessionSourceName.bv_len;
+ }
+ if ( !BER_BVISNULL( &sessionTrackingIdentifier ) ) {
+ if ( st_len ) st_len++;
+ st_len += formatOID.bv_len + STRLENOF( "=" )
+ + sessionTrackingIdentifier.bv_len;
+ }
+
+ if ( st_len == 0 ) {
+ goto error;
+ }
+
+ st_len += STRLENOF( " []" );
+ st_pos = strlen( op->o_log_prefix );
+
+ if ( sizeof( op->o_log_prefix ) - st_pos > st_len ) {
+ char *ptr = &op->o_log_prefix[ st_pos ];
+
+ ptr = lutil_strcopy( ptr, " [" /*]*/ );
+
+ st_len = 0;
+ if ( !BER_BVISNULL( &sessionSourceIp ) ) {
+ ptr = lutil_strcopy( ptr, "IP=" );
+ ptr = lutil_strcopy( ptr, sessionSourceIp.bv_val );
+ st_len++;
+ }
+
+ if ( !BER_BVISNULL( &sessionSourceName ) ) {
+ if ( st_len ) *ptr++ = ' ';
+ ptr = lutil_strcopy( ptr, "NAME=" );
+ ptr = lutil_strcopy( ptr, sessionSourceName.bv_val );
+ st_len++;
+ }
+
+ if ( !BER_BVISNULL( &sessionTrackingIdentifier ) ) {
+ if ( st_len ) *ptr++ = ' ';
+ ptr = lutil_strcopy( ptr, formatOID.bv_val );
+ *ptr++ = '=';
+ ptr = lutil_strcopy( ptr, sessionTrackingIdentifier.bv_val );
+ }
+
+ *ptr++ = /*[*/ ']';
+ *ptr = '\0';
+ }
+
+error:;
+ (void)ber_free( ber, 1 );
+
+ if ( tag == LBER_ERROR ) {
+ rs->sr_text = "sessionTracking control decoding error";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+
+ return rs->sr_err;
+}
+
+int
+slap_ctrl_session_tracking_add(
+ Operation *op,
+ SlapReply *rs,
+ struct berval *ip,
+ struct berval *name,
+ struct berval *id,
+ LDAPControl *ctrl )
+{
+ BerElementBuffer berbuf;
+ BerElement *ber = (BerElement *)&berbuf;
+
+ static struct berval oid = BER_BVC( LDAP_CONTROL_X_SESSION_TRACKING_USERNAME );
+
+ assert( ctrl != NULL );
+
+ ber_init2( ber, NULL, LBER_USE_DER );
+
+ ber_printf( ber, "{OOOO}", ip, name, &oid, id );
+
+ if ( ber_flatten2( ber, &ctrl->ldctl_value, 0 ) == -1 ) {
+ rs->sr_err = LDAP_OTHER;
+ goto done;
+ }
+
+ ctrl->ldctl_oid = LDAP_CONTROL_X_SESSION_TRACKING;
+ ctrl->ldctl_iscritical = 0;
+
+ rs->sr_err = LDAP_SUCCESS;
+
+done:;
+ return rs->sr_err;
+}
+
+int
+slap_ctrl_session_tracking_request_add( Operation *op, SlapReply *rs, LDAPControl *ctrl )
+{
+ static struct berval bv_unknown = BER_BVC( SLAP_STRING_UNKNOWN );
+ struct berval ip = BER_BVNULL,
+ name = BER_BVNULL,
+ id = BER_BVNULL;
+
+ if ( !BER_BVISNULL( &op->o_conn->c_peer_name ) &&
+ memcmp( op->o_conn->c_peer_name.bv_val, "IP=", STRLENOF( "IP=" ) ) == 0 )
+ {
+ char *ptr;
+
+ ip.bv_val = op->o_conn->c_peer_name.bv_val + STRLENOF( "IP=" );
+ ip.bv_len = op->o_conn->c_peer_name.bv_len - STRLENOF( "IP=" );
+
+ ptr = ber_bvchr( &ip, ':' );
+ if ( ptr ) {
+ ip.bv_len = ptr - ip.bv_val;
+ }
+ }
+
+ if ( !BER_BVISNULL( &op->o_conn->c_peer_domain ) &&
+ !bvmatch( &op->o_conn->c_peer_domain, &bv_unknown ) )
+ {
+ name = op->o_conn->c_peer_domain;
+ }
+
+ if ( !BER_BVISNULL( &op->o_dn ) && !BER_BVISEMPTY( &op->o_dn ) ) {
+ id = op->o_dn;
+ }
+
+ return slap_ctrl_session_tracking_add( op, rs, &ip, &name, &id, ctrl );