/* * Function: ldif_back_compare * * Returns: -1, 0 or 1 * * Description: compares entries in the ldif backend */ int ldif_back_compare( Slapi_PBlock *pb ) { LDIF *db; /*The Database*/ ldif_Entry *e, *prev; /*Used for searching the database*/ char *dn, *type; /*The dn and the type*/ struct berval *bval; Slapi_Attr *attr; int rc; LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_compare\n", 0, 0, 0 ); prev = NULL; if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db ) < 0 || slapi_pblock_get( pb, SLAPI_COMPARE_TARGET, &dn ) < 0 || slapi_pblock_get( pb, SLAPI_COMPARE_TYPE, &type ) < 0 || slapi_pblock_get( pb, SLAPI_COMPARE_VALUE, &bval ) < 0){ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); return(-1); } /*Lock the database*/ PR_Lock( db->ldif_lock ); /*Find the entry for comparison*/ if ( (e = (ldif_Entry*) ldif_find_entry( pb, db, dn, &prev )) == NULL ) { slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL ); PR_Unlock( db->ldif_lock ); return( 1 ); } /*Check the access*/ rc= slapi_access_allowed( pb, e->lde_e, type, bval, SLAPI_ACL_COMPARE ); if ( rc!=LDAP_SUCCESS ) { slapi_send_ldap_result( pb, rc, NULL, NULL, 0, NULL ); PR_Unlock( db->ldif_lock ); return( 1 ); } /*find the attribute*/ if ( slapi_entry_attr_find( e->lde_e, type, &attr ) != 0 ) { slapi_send_ldap_result( pb, LDAP_NO_SUCH_ATTRIBUTE, NULL, NULL, 0, NULL ); PR_Unlock( db->ldif_lock ); return( 1 ); } if ( slapi_attr_value_find( attr, bval ) == 0 ) { slapi_send_ldap_result( pb, LDAP_COMPARE_TRUE, NULL, NULL, 0, NULL ); PR_Unlock( db->ldif_lock ); return( 0 ); } slapi_send_ldap_result( pb, LDAP_COMPARE_FALSE, NULL, NULL, 0, NULL ); PR_Unlock( db->ldif_lock ); LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_compare\n", 0, 0, 0 ); return( 0 ); }
/* This is new style API to issue internal delete operation. pblock should contain the following data (can be set via call to slapi_delete_internal_set_pb): For uniqueid based operation: SLAPI_TARGET_DN set to dn that allows to select right backend, can be stale SLAPI_TARGET_UNIQUEID set to the uniqueid of the entry we are looking for SLAPI_CONTROLS_ARG set to request controls if present For dn based search: SLAPI_TARGET_DN set to the entry dn SLAPI_CONTROLS_ARG set to request controls if present */ int slapi_delete_internal_pb (Slapi_PBlock *pb) { if (pb == NULL) return -1; if (!allow_operation (pb)) { slapi_send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL, "This plugin is not configured to access operation target data", 0, NULL ); return 0; } return delete_internal_pb (pb); }
/* This is new style API to issue internal add operation. pblock should contain the following data (can be set via call to slapi_add_internal_set_pb): SLAPI_TARGET_SDN set to sdn of the new entry SLAPI_CONTROLS_ARG set to request controls if present SLAPI_ADD_ENTRY set to Slapi_Entry to add Beware: The entry is consumed. */ int slapi_add_internal_pb (Slapi_PBlock *pb) { if (pb == NULL) return -1; if (!allow_operation (pb)) { /* free the entry as it's expected to be consumed */ Slapi_Entry *e; slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e); slapi_pblock_set(pb, SLAPI_ADD_ENTRY, NULL); slapi_entry_free(e); slapi_send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL, "This plugin is not configured to access operation target data", 0, NULL ); return 0; } return add_internal_pb (pb); }
static int addrdnvalues_preop_add(Slapi_PBlock *pb) { int rc; Slapi_Entry *e; if (slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, "addrdnvalues_preop_add", "Error retrieving target entry\n"); return -1; } rc = slapi_entry_add_rdn_values(e); if (rc != LDAP_SUCCESS) { slapi_send_ldap_result(pb, LDAP_OTHER, NULL, "Failed to parse distinguished name", 0, NULL); slapi_log_error(SLAPI_LOG_PLUGIN, "addrdnvalues_preop_add", "Failed to parse distinguished name: %s\n", ldap_err2string(rc)); return -1; } return 0; }
int oath_preop_bind(Slapi_PBlock *pb) { char *dn; const char *creds; int creds_len, hotp_len = oath_preop_config.hotp_length, pin_len, method, rc = LDAP_SUCCESS, handled = 1; struct berval *credentials; Slapi_Value *sv_creds = NULL; Slapi_PBlock *upb, *tpb; // PBlocks for user and token searches Token token; slapi_log_error(SLAPI_LOG_PLUGIN, "oath", "oath_preop_bind\n"); if (slapi_pblock_get(pb, SLAPI_BIND_METHOD, (void *) &method) != 0 || slapi_pblock_get(pb, SLAPI_BIND_TARGET, (void *) &dn) != 0 || slapi_pblock_get(pb, SLAPI_BIND_CREDENTIALS, (void *) &credentials) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, "oath", "oath_preop_bind: Could not get parameters for bind operation\n"); slapi_send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL); return 1; } switch (method) { case LDAP_AUTH_SIMPLE: rc = LDAP_SUCCESS; sv_creds = slapi_value_new_berval(credentials); creds = slapi_value_get_string(sv_creds); creds_len = creds ? strlen(creds) : 0; Slapi_Entry **entries, *entry; int nentries = 0; upb = slapi_pblock_new(); slapi_search_internal_set_pb(upb, dn, LDAP_SCOPE_SUB, "(objectClass=*)", NULL, 0, NULL, NULL, oath_preop_plugin_id, 0); slapi_search_internal_pb(upb); slapi_pblock_get(upb, SLAPI_PLUGIN_INTOP_RESULT, &rc); slapi_pblock_get(upb, SLAPI_NENTRIES, &nentries); slapi_pblock_get(upb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); if (rc == LDAP_SUCCESS && nentries > 0 && entries != NULL && (entry = *entries) != NULL) { char filter[1024], *attrs[] = {"tokenSerial", "tokenSeed", "tokenCounter", "tokenPIN", NULL}; Slapi_Entry **tokens; int ntokens = 0; slapi_log_error(SLAPI_LOG_PLUGIN, "oath", "oath_preop_bind: Authenticating DN: %s\n", dn); // search for tokens snprintf(filter, 1024, "(&(objectClass=oathToken)(tokenOwner=%s))", dn); tpb = slapi_pblock_new(); slapi_search_internal_set_pb(tpb, oath_preop_config.token_base, LDAP_SCOPE_SUBTREE, filter, attrs, 0, NULL, NULL, oath_preop_plugin_id, 0); slapi_search_internal_pb(tpb); slapi_pblock_get(tpb, SLAPI_PLUGIN_INTOP_RESULT, &rc); slapi_pblock_get(tpb, SLAPI_NENTRIES, &ntokens); slapi_pblock_get(tpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &tokens); if (rc == LDAP_SUCCESS && ntokens > 0 && tokens != NULL) { int t, w; unsigned char hotp[hotp_len + 1]; for (t = 0; t < ntokens; t++) { oath_token_from_entry(&token, tokens[t]); pin_len = token.pin ? strlen(token.pin) : 0; slapi_log_error(SLAPI_LOG_PLUGIN, "oath", "oath_preop_bind: Found token: %s\n", token.serial); if (pin_len + hotp_len != creds_len) slapi_log_error(SLAPI_LOG_PLUGIN, "oath", "oath_preop_bind: Credentials length did not match\n"); else if (token.pin && strncmp(creds, token.pin, pin_len)) slapi_log_error(SLAPI_LOG_PLUGIN, "oath", "oath_preop_bind: PIN did not match\n"); else for (w = 0; w < oath_preop_config.hotp_inner_window; w++) { if (oath_hotp(hotp, hotp_len, token.seed->bv_val, token.seed->bv_len, token.counter + w, oath_preop_config.hotp_trunc_offset, oath_preop_config.hotp_checksum)) { // slapi_log_error(SLAPI_LOG_PLUGIN, "oath", "oath_preop_bind: hotp(%d) = %s\n", token.counter + w, hotp); if (!strncmp(hotp, creds + pin_len, hotp_len)) { // success slapi_log_error(SLAPI_LOG_PLUGIN, "oath", "oath_preop_bind: hotp(%d) = %s\n", token.counter + w, hotp); if (oath_update_token(tokens[t], token.counter + w + 1) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, "oath", "oath_preop_bind: Failed to update token entry\n"); rc = LDAP_OPERATIONS_ERROR; }; // OpenLDAP does not support setting SLAPI_CONN_DN and SLAPI_CONN_AUTHMETHOD /* if (slapi_pblock_set(pb, SLAPI_CONN_DN, slapi_ch_strdup(dn)) != 0 || slapi_pblock_set(pb, SLAPI_CONN_AUTHMETHOD, SLAPD_AUTH_SIMPLE) != 0) { slapi_log_error(SLAPI_LOG_PLUGIN, "oath", "oath_preop_bind: Failed to set DN and auth method for connection\n", dn); rc = LDAP_OPERATIONS_ERROR; } */ goto free_tpb; } } else { // HOTP error slapi_log_error(SLAPI_LOG_PLUGIN, "oath", "oath_preop_bind: HOTP error for token %s\n", token.serial); break; } } slapi_log_error(SLAPI_LOG_PLUGIN, "oath", "oath_preop_bind: Token %s did not match\n", token.serial); oath_token_free(&token); } // No token matched handled = 0; goto free_tpb; } else { // no tokens associated slapi_log_error(SLAPI_LOG_PLUGIN, "oath", "oath_preop_bind: DN %s has got no token(s) associated, rc = %d\n", dn, rc); handled = 0; goto free_upb; } } else { // entry not found; don't fail because this can be root (directory manager) DN slapi_log_error(SLAPI_LOG_PLUGIN, "oath", "oath_preop_bind: DN %s not found\n", dn); if (rc == LDAP_SUCCESS) rc = LDAP_OPERATIONS_ERROR; else handled = 0; goto free_upb; } break; case LDAP_AUTH_NONE: case LDAP_AUTH_SASL: default: slapi_log_error(SLAPI_LOG_PLUGIN, "oath", "oath_bind_preop: Authentication type not supported: %d", method); return 0; } free_tpb: oath_token_free(&token); slapi_free_search_results_internal(tpb); slapi_pblock_destroy(tpb); free_upb: slapi_free_search_results_internal(upb); slapi_pblock_destroy(upb); slapi_value_free(&sv_creds); if (handled) { slapi_send_ldap_result(pb, rc, NULL, NULL, 0, NULL); return 1; } else return 0; }
int ldbm_back_bind( Slapi_PBlock *pb ) { backend *be; ldbm_instance *inst; int method; struct berval *cred; struct ldbminfo *li; struct backentry *e; Slapi_Attr *attr; Slapi_Value **bvals; entry_address *addr; back_txn txn = {NULL}; /* get parameters */ slapi_pblock_get( pb, SLAPI_BACKEND, &be ); slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li ); slapi_pblock_get( pb, SLAPI_TARGET_ADDRESS, &addr ); slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method ); slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &cred ); slapi_pblock_get( pb, SLAPI_TXN, &txn.back_txn_txn ); if ( !txn.back_txn_txn ) { dblayer_txn_init( li, &txn ); slapi_pblock_set( pb, SLAPI_TXN, txn.back_txn_txn ); } inst = (ldbm_instance *) be->be_instance_info; /* always allow noauth simple binds (front end will send the result) */ if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 ) { return( SLAPI_BIND_ANONYMOUS ); } /* * find the target entry. find_entry() takes care of referrals * and sending errors if the entry does not exist. */ if (( e = find_entry( pb, be, addr, &txn )) == NULL ) { return( SLAPI_BIND_FAIL ); } switch ( method ) { case LDAP_AUTH_SIMPLE: { Slapi_Value cv; if ( slapi_entry_attr_find( e->ep_entry, "userpassword", &attr ) != 0 ) { #if defined( XP_WIN32 ) if( WindowsAuthentication( e, cred ) == LDAPWA_Success ) { break; } #endif slapi_send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL, NULL, 0, NULL ); CACHE_RETURN( &inst->inst_cache, &e ); return( SLAPI_BIND_FAIL ); } bvals= attr_get_present_values(attr); slapi_value_init_berval(&cv,cred); if ( slapi_pw_find_sv( bvals, &cv ) != 0 ) { #if defined( XP_WIN32 ) /* One last try - attempt Windows authentication, if the user has a Windows account. */ if( WindowsAuthentication( e, cred ) == LDAPWA_Success ) { break; } #endif slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL ); CACHE_RETURN( &inst->inst_cache, &e ); value_done(&cv); return( SLAPI_BIND_FAIL ); } value_done(&cv); } break; default: slapi_send_ldap_result( pb, LDAP_STRONG_AUTH_NOT_SUPPORTED, NULL, "auth method not supported", 0, NULL ); CACHE_RETURN( &inst->inst_cache, &e ); return( SLAPI_BIND_FAIL ); } CACHE_RETURN( &inst->inst_cache, &e ); /* success: front end will send result */ return( SLAPI_BIND_SUCCESS ); }
/* * Access the database sequentially. * There are 4 ways to call this routine. In each case, the equality index * for "attrname" is consulted: * 1) If the SLAPI_SEQ_TYPE parameter is SLAPI_SEQ_FIRST, then this routine * will find the smallest key greater than or equal to the SLAPI_SEQ_VAL * parameter, and return all entries that key's IDList. If SLAPI_SEQ_VAL * is NULL, then the smallest key is retrieved and the associaated * entries are returned. * 2) If the SLAPI_SEQ_TYPE parameter is SLAPI_SEQ_NEXT, then this routine * will find the smallest key strictly greater than the SLAPI_SEQ_VAL * parameter, and return all entries that key's IDList. * 3) If the SLAPI_SEQ_TYPE parameter is SLAPI_SEQ_PREV, then this routine * will find the greatest key strictly less than the SLAPI_SEQ_VAL * parameter, and return all entries that key's IDList. * 4) If the SLAPI_SEQ_TYPE parameter is SLAPI_SEQ_LAST, then this routine * will find the largest equality key in the index and return all entries * which match that key. The SLAPI_SEQ_VAL parameter is ignored. */ int ldbm_back_seq( Slapi_PBlock *pb ) { backend *be; ldbm_instance *inst; struct ldbminfo *li; IDList *idl = NULL; back_txn txn = {NULL}; back_txnid parent_txn; struct attrinfo *ai = NULL; DB *db; DBC *dbc = NULL; char *attrname, *val; int err = LDAP_SUCCESS; int return_value = -1; int nentries = 0; int retry_count = 0; int isroot; int type; /* Decode arguments */ slapi_pblock_get( pb, SLAPI_BACKEND, &be); slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li ); slapi_pblock_get( pb, SLAPI_SEQ_TYPE, &type ); slapi_pblock_get( pb, SLAPI_SEQ_ATTRNAME, &attrname ); slapi_pblock_get( pb, SLAPI_SEQ_VAL, &val ); slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot ); slapi_pblock_get( pb, SLAPI_TXN, (void **)&parent_txn ); inst = (ldbm_instance *) be->be_instance_info; dblayer_txn_init( li, &txn ); if (!parent_txn) { parent_txn = txn.back_txn_txn; slapi_pblock_set( pb, SLAPI_TXN, parent_txn ); } /* Validate arguments */ if ( type != SLAPI_SEQ_FIRST && type != SLAPI_SEQ_LAST && type != SLAPI_SEQ_NEXT && type != SLAPI_SEQ_PREV ) { slapi_send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "Bad seq access type", 0, NULL ); return( -1 ); } /* get a database */ ainfo_get( be, attrname, &ai ); slapi_log_err(SLAPI_LOG_ARGS, "ldbm_back_seq", "indextype: %s indexmask: 0x%x seek type: %d\n", ai->ai_type, ai->ai_indexmask, type ); if ( ! (INDEX_EQUALITY & ai->ai_indexmask) ) { slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_seq", "caller specified un-indexed attribute %s\n", attrname ? attrname : ""); slapi_send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Unindexed seq access type", 0, NULL ); return -1; } if ( (return_value = dblayer_get_index_file( be, ai, &db, DBOPEN_CREATE )) != 0 ) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_seq", "Could not open index file for attribute %s\n", attrname); slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); return -1; } retry: if (txn.back_txn_txn) { dblayer_read_txn_begin(be, parent_txn, &txn); } /* First, get a database cursor */ return_value = db->cursor(db, txn.back_txn_txn, &dbc, 0); if (0 == return_value) { DBT data = {0}; DBT key = {0}; char little_buffer[SEQ_LITTLE_BUFFER_SIZE]; char *big_buffer = NULL; char keystring = EQ_PREFIX; /* Set data */ data.flags = DB_DBT_MALLOC; /* Set up key */ key.flags = DB_DBT_MALLOC; if (NULL == val) { /* this means, goto the first equality key */ /* seek to key >= "=" */ key.data = &keystring; key.size = 1; } else { size_t key_length = strlen(val) + 2; if (key_length <= SEQ_LITTLE_BUFFER_SIZE) { key.data = &little_buffer; } else { big_buffer = slapi_ch_malloc(key_length); if (NULL == big_buffer) { /* memory allocation failure */ dblayer_release_index_file( be, ai, db ); return -1; } key.data = big_buffer; } key.size = sprintf(key.data,"%c%s",EQ_PREFIX,val); } /* decide which type of operation we're being asked to do and do the db bit */ /* The c_get call always mallocs memory for data.data */ /* The c_get call mallocs memory for key.data, except for DB_SET */ /* after this, we leave data containing the retrieved IDL, or NULL if we didn't get it */ switch (type) { case SLAPI_SEQ_FIRST: /* if (NULL == val) goto the first equality key ( seek to key >= "=" ) */ /* else goto the first equality key >= val ( seek to key >= "=val" )*/ return_value = dbc->c_get(dbc,&key,&data,DB_SET_RANGE); break; case SLAPI_SEQ_NEXT: /* seek to the indicated =value, then seek to the next entry, */ return_value = dbc->c_get(dbc,&key,&data,DB_SET); if (0 == return_value) { slapi_ch_free(&(data.data)); return_value = dbc->c_get(dbc,&key,&data,DB_NEXT); } else { /* DB_SET doesn't allocate key data. Make sure we don't try to free it... */ key.data= NULL; } break; case SLAPI_SEQ_PREV: /* seek to the indicated =value, then seek to the previous entry, */ return_value = dbc->c_get(dbc,&key,&data,DB_SET); if (0 == return_value ) { slapi_ch_free(&(data.data)); return_value = dbc->c_get(dbc,&key,&data,DB_PREV); } else { /* DB_SET doesn't allocate key data. Make sure we don't try to free it... */ key.data= NULL; } break; case SLAPI_SEQ_LAST: /* seek to the first possible key after all the equality keys (">"), then seek back one */ { keystring = EQ_PREFIX + 1; key.data = &keystring; key.size = 1; return_value = dbc->c_get(dbc,&key,&data,DB_SET_RANGE); if ((0 == return_value) || (DB_NOTFOUND == return_value)) { slapi_ch_free(&(data.data)); return_value = dbc->c_get(dbc,&key,&data,DB_PREV); } } break; } dbc->c_close(dbc); if ((0 == return_value) || (DB_NOTFOUND == return_value)) { /* Now check that the key we eventually settled on was an equality key ! */ if (key.data && *((char*)key.data) == EQ_PREFIX) { /* Retrieve the idlist for this key */ key.flags = 0; for (retry_count = 0; retry_count < IDL_FETCH_RETRY_COUNT; retry_count++) { err = NEW_IDL_DEFAULT; idl_free(&idl); idl = idl_fetch( be, db, &key, parent_txn, ai, &err ); if(err == DB_LOCK_DEADLOCK) { ldbm_nasty("ldbm_back_seq", "deadlock retry", 1600, err); if (txn.back_txn_txn) { /* just in case */ slapi_ch_free(&(data.data)); if ((key.data != little_buffer) && (key.data != &keystring)) { slapi_ch_free(&(key.data)); } dblayer_read_txn_abort(be, &txn); goto retry; } else { continue; } } else { break; } } } } else { if (txn.back_txn_txn) { dblayer_read_txn_abort(be, &txn); } if (DB_LOCK_DEADLOCK == return_value) { ldbm_nasty("ldbm_back_seq", "deadlock retry", 1601, err); /* just in case */ slapi_ch_free(&(data.data)); if ((key.data != little_buffer) && (key.data != &keystring)) { slapi_ch_free(&(key.data)); } goto retry; } } if(retry_count == IDL_FETCH_RETRY_COUNT) { ldbm_nasty("ldbm_back_seq", "Retry count exceeded",1645,err); } else if ( err != 0 && err != DB_NOTFOUND ) { ldbm_nasty("ldbm_back_seq", "Database error", 1650, err); } slapi_ch_free( &(data.data) ); if ( key.data != little_buffer && key.data != &keystring ) { slapi_ch_free( &(key.data) ); } slapi_ch_free_string( &big_buffer ); } /* null idlist means there were no matching keys */ if ( idl != NULL ) { /* * Step through the IDlist. For each ID, get the entry * and send it. */ ID id; struct backentry *e; for ( id = idl_firstid( idl ); id != NOID; id = idl_nextid( idl, id )) { if (( e = id2entry( be, id, &txn, &err )) == NULL ) { if ( err != LDAP_SUCCESS ) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_seq", "id2entry err %d\n", err); } slapi_log_err(SLAPI_LOG_ARGS, "ldbm_back_seq", "candidate %lu not found\n", (u_long)id); continue; } if ( slapi_send_ldap_search_entry( pb, e->ep_entry, NULL, NULL, 0 ) == 0 ) { nentries++; } CACHE_RETURN( &inst->inst_cache, &e ); } idl_free( &idl ); } /* if success finally commit the transaction, otherwise abort if DB_NOTFOUND */ if(txn.back_txn_txn){ if (return_value == 0) { dblayer_read_txn_commit(be, &txn); } else if (DB_NOTFOUND == return_value){ dblayer_read_txn_abort(be, &txn); } } dblayer_release_index_file( be, ai, db ); slapi_send_ldap_result( pb, LDAP_SUCCESS == err ? LDAP_SUCCESS : LDAP_OPERATIONS_ERROR, NULL, NULL, nentries, NULL ); return 0; }
static int passthru_bindpreop( Slapi_PBlock *pb ) { int rc, method, freeresctrls=1; char *matcheddn; const char *normbinddn = NULL; Slapi_DN *sdn = NULL; char *libldap_errmsg, *pr_errmsg, *errmsg; PassThruConfig *cfg; PassThruServer *srvr; struct berval *creds, **urls; LDAPControl **reqctrls, **resctrls; PASSTHRU_ASSERT( pb != NULL ); slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, "=> passthru_bindpreop\n" ); /* * retrieve parameters for bind operation */ if ( slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method ) != 0 || slapi_pblock_get( pb, SLAPI_BIND_TARGET_SDN, &sdn ) != 0 || slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &creds ) != 0 ) { slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, "<= not handled (unable to retrieve bind parameters)\n" ); return( PASSTHRU_OP_NOT_HANDLED ); } normbinddn = slapi_sdn_get_dn(sdn); if ( normbinddn == NULL ) { normbinddn = ""; } /* * We only handle simple bind requests that include non-NULL binddn and * credentials. Let the Directory Server itself handle everything else. */ if ( method != LDAP_AUTH_SIMPLE || *normbinddn == '\0' || creds->bv_len == 0 ) { slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, "<= not handled (not simple bind or NULL dn/credentials)\n" ); return( PASSTHRU_OP_NOT_HANDLED ); } /* * Get pass through authentication configuration. */ cfg = passthru_get_config(); /* * Check to see if the target DN is one we should "pass through" to * another server. */ if ( passthru_dn2server( cfg, normbinddn, &srvr ) != LDAP_SUCCESS ) { slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, "<= not handled (not one of our suffixes)\n" ); return( PASSTHRU_OP_NOT_HANDLED ); } /* * We are now committed to handling this bind request. * Chain it off to another server. */ matcheddn = errmsg = libldap_errmsg = pr_errmsg = NULL; urls = NULL; resctrls = NULL; if ( slapi_pblock_get( pb, SLAPI_REQCONTROLS, &reqctrls ) != 0 ) { rc = LDAP_OPERATIONS_ERROR; errmsg = "unable to retrieve bind controls"; slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, "%s\n", errmsg ); } else { int lderrno; if (( rc = passthru_simple_bind_s( pb, srvr, PASSTHRU_CONN_TRIES, normbinddn, creds, reqctrls, &lderrno, &matcheddn, &libldap_errmsg, &urls, &resctrls )) == LDAP_SUCCESS ) { rc = lderrno; errmsg = libldap_errmsg; } else if ( rc != LDAP_USER_CANCELLED ) { /* not abandoned */ PRErrorCode prerr = PR_GetError(); pr_errmsg = PR_smprintf( "error %d - %s %s (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)", rc, ldap_err2string( rc ), srvr->ptsrvr_url, prerr, slapd_pr_strerror(prerr)); if ( NULL != pr_errmsg ) { errmsg = pr_errmsg; } else { errmsg = ldap_err2string( rc ); } rc = LDAP_OPERATIONS_ERROR; } } /* * If bind succeeded, change authentication information associated * with this connection. */ if ( rc == LDAP_SUCCESS ) { char *ndn = slapi_ch_strdup( normbinddn ); if (slapi_pblock_set(pb, SLAPI_CONN_DN, ndn) != 0 || slapi_pblock_set(pb, SLAPI_CONN_AUTHMETHOD, SLAPD_AUTH_SIMPLE) != 0) { slapi_ch_free((void **)&ndn); rc = LDAP_OPERATIONS_ERROR; errmsg = "unable to set connection DN or AUTHTYPE"; slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, "%s\n", errmsg ); } } if ( rc != LDAP_USER_CANCELLED ) { /* not abandoned */ /* * Send a result to our client. */ if ( resctrls != NULL ) { (void)slapi_pblock_set( pb, SLAPI_RESCONTROLS, resctrls ); freeresctrls=0; } slapi_send_ldap_result( pb, rc, matcheddn, errmsg, 0, urls ); } /* * Clean up -- free allocated memory, etc. */ if ( urls != NULL ) { passthru_free_bervals( urls ); } if ( libldap_errmsg != NULL ) { ldap_memfree( errmsg ); } if ( pr_errmsg != NULL ) { PR_smprintf_free( pr_errmsg ); } if ( freeresctrls && (resctrls != NULL) ) { ldap_controls_free( resctrls ); } if ( matcheddn != NULL ) { ldap_memfree( matcheddn ); } slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM, "<= handled (error %d - %s)\n", rc, ldap_err2string( rc )); return( PASSTHRU_OP_HANDLED ); }
/* * preop_modrdn - Pre-operation call for modify RDN * * Check that the new RDN does not include attributes that * cause a constraint violation */ static int preop_modrdn(Slapi_PBlock *pb) { int result = LDAP_SUCCESS; Slapi_Entry *e = NULL; Slapi_Value *sv_requiredObjectClass = NULL; char *errtext = NULL; char *attrName = NULL; #ifdef DEBUG slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "MODRDN begin\n"); #endif BEGIN int err; char *markerObjectClass=NULL; char *requiredObjectClass=NULL; Slapi_DN *sdn = NULL; Slapi_DN *superior; char *rdn; int deloldrdn = 0; int isupdatedn; Slapi_Attr *attr; int argc; char **argv = NULL; /* * If this is a replication update, just be a noop. */ err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &isupdatedn); if (err) { result = uid_op_error(30); break; } if (isupdatedn) { break; } /* * Get the arguments */ result = getArguments(pb, &attrName, &markerObjectClass, &requiredObjectClass); if (UNTAGGED_PARAMETER == result) { result = LDAP_SUCCESS; /* Statically defined subtrees to monitor */ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc); if (err) { result = uid_op_error(53); break; } err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv); if (err) { result = uid_op_error(54); break; } argc--; /* First argument was attribute name */ argv++; } else if (0 != result) { break; } /* Create a Slapi_Value for the requiredObjectClass to use * for checking the entry. */ if (requiredObjectClass) { sv_requiredObjectClass = slapi_value_new_string(requiredObjectClass); } /* Get the DN of the entry being renamed */ err = slapi_pblock_get(pb, SLAPI_MODRDN_TARGET_SDN, &sdn); if (err) { result = uid_op_error(31); break; } /* Get superior value - unimplemented in 3.0/4.0/5.0 DS */ err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &superior); if (err) { result = uid_op_error(32); break; } /* * No superior means the entry is just renamed at * its current level in the tree. Use the target DN for * determining which managed tree this belongs to */ if (!superior) superior = sdn; /* Get the new RDN - this has the attribute values */ err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &rdn); if (err) { result = uid_op_error(33); break; } #ifdef DEBUG slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "MODRDN newrdn=%s\n", rdn); #endif /* See if the old RDN value is being deleted. */ err = slapi_pblock_get(pb, SLAPI_MODRDN_DELOLDRDN, &deloldrdn); if (err) { result = uid_op_error(34); break; } /* Get the entry that is being renamed so we can make a dummy copy * of what it will look like after the rename. */ err = slapi_search_internal_get_entry(sdn, NULL, &e, plugin_identity); if (err != LDAP_SUCCESS) { result = uid_op_error(35); /* We want to return a no such object error if the target doesn't exist. */ if (err == LDAP_NO_SUCH_OBJECT) { result = err; } break; } /* Apply the rename operation to the dummy entry. */ /* slapi_entry_rename does not expect rdn normalized */ err = slapi_entry_rename(e, rdn, deloldrdn, superior); if (err != LDAP_SUCCESS) { result = uid_op_error(36); break; } /* * Find any unique attribute data in the new RDN */ err = slapi_entry_attr_find(e, attrName, &attr); if (err) break; /* no UID attribute */ /* * Check if it has the required object class */ if (requiredObjectClass && !slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS, sv_requiredObjectClass)) { break; } /* * Passed all the requirements - this is an operation we * need to enforce uniqueness on. Now find all parent entries * with the marker object class, and do a search for each one. */ if (NULL != markerObjectClass) { /* Subtree defined by location of marker object class */ result = findSubtreeAndSearch(slapi_entry_get_sdn(e), attrName, attr, NULL, requiredObjectClass, sdn, markerObjectClass); } else { /* Subtrees listed on invocation line */ result = searchAllSubtrees(argc, argv, attrName, attr, NULL, requiredObjectClass, sdn); } END /* Clean-up */ slapi_value_free(&sv_requiredObjectClass); if (e) slapi_entry_free(e); if (result) { slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "MODRDN result %d\n", result); if (result == LDAP_CONSTRAINT_VIOLATION) { errtext = slapi_ch_smprintf(moreInfo, attrName); } else { errtext = slapi_ch_strdup("Error checking for attribute uniqueness."); } slapi_send_ldap_result(pb, result, 0, errtext, 0, 0); slapi_ch_free_string(&errtext); } return (result==LDAP_SUCCESS)?0:-1; }
/* * preop_modify - pre-operation plug-in for modify */ static int preop_modify(Slapi_PBlock *pb) { int result = LDAP_SUCCESS; Slapi_PBlock *spb = NULL; LDAPMod **checkmods = NULL; int checkmodsCapacity = 0; char *errtext = NULL; char *attrName = NULL; #ifdef DEBUG slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "MODIFY begin\n"); #endif BEGIN int err; char *markerObjectClass=NULL; char *requiredObjectClass=NULL; LDAPMod **mods; int modcount = 0; int ii; LDAPMod *mod; Slapi_DN *sdn = NULL; int isupdatedn; int argc; char **argv = NULL; /* * If this is a replication update, just be a noop. */ err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &isupdatedn); if (err) { result = uid_op_error(60); break; } if (isupdatedn) { break; } /* * Get the arguments */ result = getArguments(pb, &attrName, &markerObjectClass, &requiredObjectClass); if (UNTAGGED_PARAMETER == result) { result = LDAP_SUCCESS; /* Statically defined subtrees to monitor */ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc); if (err) { result = uid_op_error(53); break; } err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv); if (err) { result = uid_op_error(54); break; } argc--; /* First argument was attribute name */ argv++; } else if (0 != result) { break; } err = slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods); if (err) { result = uid_op_error(61); break; } /* There may be more than one mod that matches e.g. changetype: modify delete: uid uid: balster1950 - add: uid uid: scottg So, we need to first find all mods that contain the attribute which are add or replace ops and are bvalue encoded */ /* find out how many mods meet this criteria */ for(;*mods;mods++) { mod = *mods; if ((slapi_attr_type_cmp(mod->mod_type, attrName, 1) == 0) && /* mod contains target attr */ (mod->mod_op & LDAP_MOD_BVALUES) && /* mod is bval encoded (not string val) */ (mod->mod_bvalues && mod->mod_bvalues[0]) && /* mod actually contains some values */ (SLAPI_IS_MOD_ADD(mod->mod_op) || /* mod is add */ SLAPI_IS_MOD_REPLACE(mod->mod_op))) /* mod is replace */ { addMod(&checkmods, &checkmodsCapacity, &modcount, mod); } } if (modcount == 0) { break; /* no mods to check, we are done */ } /* Get the target DN */ err = slapi_pblock_get(pb, SLAPI_MODIFY_TARGET_SDN, &sdn); if (err) { result = uid_op_error(11); break; } /* * Check if it has the required object class */ if (requiredObjectClass && !(spb = dnHasObjectClass(sdn, requiredObjectClass))) { break; } /* * Passed all the requirements - this is an operation we * need to enforce uniqueness on. Now find all parent entries * with the marker object class, and do a search for each one. */ /* * stop checking at first mod that fails the check */ for (ii = 0; (result == 0) && (ii < modcount); ++ii) { mod = checkmods[ii]; if (NULL != markerObjectClass) { /* Subtree defined by location of marker object class */ result = findSubtreeAndSearch(sdn, attrName, NULL, mod->mod_bvalues, requiredObjectClass, sdn, markerObjectClass); } else { /* Subtrees listed on invocation line */ result = searchAllSubtrees(argc, argv, attrName, NULL, mod->mod_bvalues, requiredObjectClass, sdn); } } END slapi_ch_free((void **)&checkmods); freePblock(spb); if (result) { slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "MODIFY result %d\n", result); if (result == LDAP_CONSTRAINT_VIOLATION) { errtext = slapi_ch_smprintf(moreInfo, attrName); } else { errtext = slapi_ch_strdup("Error checking for attribute uniqueness."); } slapi_send_ldap_result(pb, result, 0, errtext, 0, 0); slapi_ch_free_string(&errtext); } return (result==LDAP_SUCCESS)?0:-1; }
/* * preop_add - pre-operation plug-in for add */ static int preop_add(Slapi_PBlock *pb) { int result; char *errtext = NULL; char *attrName = NULL; #ifdef DEBUG slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "ADD begin\n"); #endif result = LDAP_SUCCESS; /* * Do constraint check on the added entry. Set result. */ BEGIN int err; char *markerObjectClass = NULL; char *requiredObjectClass = NULL; Slapi_DN *sdn = NULL; int isupdatedn; Slapi_Entry *e; Slapi_Attr *attr; int argc; char **argv = NULL; /* * If this is a replication update, just be a noop. */ err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &isupdatedn); if (err) { result = uid_op_error(50); break; } if (isupdatedn) { break; } /* * Get the arguments */ result = getArguments(pb, &attrName, &markerObjectClass, &requiredObjectClass); if (UNTAGGED_PARAMETER == result) { slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "ADD parameter untagged: %s\n", attrName); result = LDAP_SUCCESS; /* Statically defined subtrees to monitor */ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc); if (err) { result = uid_op_error(53); break; } err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv); if (err) { result = uid_op_error(54); break; } argc--; argv++; /* First argument was attribute name */ } else if (0 != result) { break; } /* * Get the target DN for this add operation */ err = slapi_pblock_get(pb, SLAPI_ADD_TARGET_SDN, &sdn); if (err) { result = uid_op_error(51); break; } #ifdef DEBUG slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "ADD target=%s\n", slapi_sdn_get_dn(sdn)); #endif /* * Get the entry data for this add. Check whether it * contains a value for the unique attribute */ err = slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e); if (err) { result = uid_op_error(52); break; } err = slapi_entry_attr_find(e, attrName, &attr); if (err) break; /* no unique attribute */ /* * Check if it contains the required object class */ if (NULL != requiredObjectClass) { if (!entryHasObjectClass(pb, e, requiredObjectClass)) { /* No, so we don't have to do anything */ break; } } /* * Passed all the requirements - this is an operation we * need to enforce uniqueness on. Now find all parent entries * with the marker object class, and do a search for each one. */ if (NULL != markerObjectClass) { /* Subtree defined by location of marker object class */ result = findSubtreeAndSearch(sdn, attrName, attr, NULL, requiredObjectClass, sdn, markerObjectClass); } else { /* Subtrees listed on invocation line */ result = searchAllSubtrees(argc, argv, attrName, attr, NULL, requiredObjectClass, sdn); } END if (result) { slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "ADD result %d\n", result); if (result == LDAP_CONSTRAINT_VIOLATION) { errtext = slapi_ch_smprintf(moreInfo, attrName); } else { errtext = slapi_ch_strdup("Error checking for attribute uniqueness."); } /* Send failure to the client */ slapi_send_ldap_result(pb, result, 0, errtext, 0, 0); slapi_ch_free_string(&errtext); } return (result==LDAP_SUCCESS)?0:-1; }
static int nullsuffix_search( Slapi_PBlock *pb ) { char *dn_base, **attrs, *newStr; int scope, sizelimit, timelimit, deref, attrsonly; Slapi_Filter *filter; Slapi_DN *sdn_base; int ldaperr = LDAP_SUCCESS; /* optimistic */ int nentries = 0; /* entry count */ int i; Slapi_Operation *op; Slapi_Entry *e; const char *entrystr = "dn:cn=Joe Smith,o=Example\n" "objectClass: top\n" "objectClass: person\n" "objectClass: organizationalPerson\n" "objectClass: inetOrgPerson\n" "cn:Joe Smith\n" "sn:Smith\n" "uid:jsmith\n" "mail:[email protected]\n"; slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "nullsuffix_search\n" ); if( slapi_op_reserved(pb) ){ return PLUGIN_OPERATION_IGNORED; } /* get essential search parameters */ if ( slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &dn_base ) != 0 || slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope ) != 0 ) { slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "could not get base DN and scope search parameters\n" ); } if ( dn_base == NULL ) { dn_base = ""; } sdn_base = slapi_sdn_new_dn_byval( dn_base ); slapi_pblock_get(pb, SLAPI_OPERATION, &op); /* get remaining search parameters */ if ( slapi_pblock_get( pb, SLAPI_SEARCH_DEREF, &deref ) != 0 || slapi_pblock_get( pb, SLAPI_SEARCH_SIZELIMIT, &sizelimit ) != 0 || slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &timelimit ) != 0 || slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter ) != 0 || slapi_pblock_get( pb, SLAPI_SEARCH_ATTRS, &attrs ) != 0 || slapi_pblock_get( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly ) != 0 ) { slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "could not get remaining search parameters\n" ); } if ( slapi_pblock_get( pb, SLAPI_OPERATION, &op ) != 0 ) { slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "could not get operation\n" ); } else { slapi_operation_set_flag(op, SLAPI_OP_FLAG_NO_ACCESS_CHECK ); } /* create a fake entry and send it along */ newStr = slapi_ch_strdup( entrystr ); if ( NULL == ( e = slapi_str2entry( newStr, SLAPI_STR2ENTRY_ADDRDNVALS | SLAPI_STR2ENTRY_EXPAND_OBJECTCLASSES ))) { slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "nullsuffix_search: slapi_str2entry() failed\n" ); } else { slapi_send_ldap_search_entry( pb, e, NULL /* controls */, attrs, attrsonly ); ++nentries; slapi_entry_free( e ); } slapi_send_ldap_result( pb, ldaperr, NULL, "kilroy was here", nentries, NULL ); slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "nullsuffix_search:" " handled search based at %s with scope %d; ldaperr=%d\n", dn_base, scope, ldaperr ); slapi_ch_free_string(&newStr); slapi_sdn_free(&sdn_base); return PLUGIN_OPERATION_HANDLED; }
int ldbm_back_modify( Slapi_PBlock *pb ) { backend *be; ldbm_instance *inst = NULL; struct ldbminfo *li; struct backentry *e = NULL, *ec = NULL; struct backentry *original_entry = NULL, *tmpentry = NULL; Slapi_Entry *postentry = NULL; LDAPMod **mods = NULL; LDAPMod **mods_original = NULL; Slapi_Mods smods = {0}; back_txn txn; back_txnid parent_txn; modify_context ruv_c = {0}; int ruv_c_init = 0; int retval = -1; char *msg; char *errbuf = NULL; int retry_count = 0; int disk_full = 0; int ldap_result_code= LDAP_SUCCESS; char *ldap_result_message= NULL; int rc = 0; Slapi_Operation *operation; entry_address *addr; int is_fixup_operation= 0; int is_ruv = 0; /* True if the current entry is RUV */ CSN *opcsn = NULL; int repl_op; int opreturn = 0; int mod_count = 0; int not_an_error = 0; int fixup_tombstone = 0; int ec_locked = 0; int result_sent = 0; slapi_pblock_get( pb, SLAPI_BACKEND, &be); slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li ); slapi_pblock_get( pb, SLAPI_TARGET_ADDRESS, &addr ); slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods ); slapi_pblock_get( pb, SLAPI_TXN, (void**)&parent_txn ); slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op); slapi_pblock_get( pb, SLAPI_OPERATION, &operation ); fixup_tombstone = operation_is_flag_set(operation, OP_FLAG_TOMBSTONE_FIXUP); dblayer_txn_init(li,&txn); /* must do this before first goto error_return */ /* the calls to perform searches require the parent txn if any so set txn to the parent_txn until we begin the child transaction */ if (parent_txn) { txn.back_txn_txn = parent_txn; } else { parent_txn = txn.back_txn_txn; slapi_pblock_set( pb, SLAPI_TXN, parent_txn ); } if (NULL == operation) { ldap_result_code = LDAP_OPERATIONS_ERROR; goto error_return; } is_fixup_operation = operation_is_flag_set(operation, OP_FLAG_REPL_FIXUP); is_ruv = operation_is_flag_set(operation, OP_FLAG_REPL_RUV); inst = (ldbm_instance *) be->be_instance_info; if (NULL == addr) { goto error_return; } if (inst && inst->inst_ref_count) { slapi_counter_increment(inst->inst_ref_count); } else { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "Instance \"%s\" does not exist.\n", inst ? inst->inst_name : "null instance"); goto error_return; } /* no need to check the dn syntax as this is a replicated op */ if(!repl_op){ ldap_result_code = slapi_dn_syntax_check(pb, slapi_sdn_get_dn(addr->sdn), 1); if (ldap_result_code) { ldap_result_code = LDAP_INVALID_DN_SYNTAX; slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message); goto error_return; } } /* The dblock serializes writes to the database, * which reduces deadlocking in the db code, * which means that we run faster. * * But, this lock is re-enterant for the fixup * operations that the URP code in the Replication * plugin generates. * * SERIALLOCK is moved to dblayer_txn_begin along with exposing be * transaction to plugins (see slapi_back_transaction_* APIs). * if(SERIALLOCK(li) && !operation_is_flag_set(operation,OP_FLAG_REPL_FIXUP)) { dblayer_lock_backend(be); dblock_acquired= 1; } */ if ( MANAGE_ENTRY_BEFORE_DBLOCK(li)) { /* find and lock the entry we are about to modify */ if (fixup_tombstone) { e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn, &result_sent ); } else { e = find_entry2modify( pb, be, addr, &txn, &result_sent ); } if (e == NULL) { ldap_result_code = -1; goto error_return; /* error result sent by find_entry2modify() */ } } txn.back_txn_txn = NULL; /* ready to create the child transaction */ for (retry_count = 0; retry_count < RETRY_TIMES; retry_count++) { int cache_rc = 0; int new_mod_count = 0; if (txn.back_txn_txn && (txn.back_txn_txn != parent_txn)) { /* don't release SERIAL LOCK */ dblayer_txn_abort_ext(li, &txn, PR_FALSE); slapi_pblock_set(pb, SLAPI_TXN, parent_txn); /* * Since be_txn_preop functions could have modified the entry/mods, * We need to grab the current mods, free them, and restore the * originals. Same thing for the entry. */ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods); ldap_mods_free(mods, 1); slapi_pblock_set(pb, SLAPI_MODIFY_MODS, copy_mods(mods_original)); /* reset ec set cache in id2entry_add_ext */ if (ec) { /* must duplicate ec before returning it to cache, * which could free the entry. */ if ((tmpentry = backentry_dup(original_entry?original_entry:ec)) == NULL) { ldap_result_code= LDAP_OPERATIONS_ERROR; goto error_return; } if (cache_is_in_cache(&inst->inst_cache, ec)) { CACHE_REMOVE(&inst->inst_cache, ec); } CACHE_RETURN(&inst->inst_cache, &ec); slapi_pblock_set( pb, SLAPI_MODIFY_EXISTING_ENTRY, original_entry->ep_entry ); ec = original_entry; original_entry = tmpentry; tmpentry = NULL; } if (ruv_c_init) { /* reset the ruv txn stuff */ modify_term(&ruv_c, be); ruv_c_init = 0; } slapi_log_err(SLAPI_LOG_BACKLDBM, "ldbm_back_modify", "Modify Retrying Transaction\n"); #ifndef LDBM_NO_BACKOFF_DELAY { PRIntervalTime interval; interval = PR_MillisecondsToInterval(slapi_rand() % 100); DS_Sleep(interval); } #endif } /* Nothing above here modifies persistent store, everything after here is subject to the transaction */ /* dblayer_txn_begin holds SERIAL lock, * which should be outside of locking the entry (find_entry2modify) */ if (0 == retry_count) { /* First time, hold SERIAL LOCK */ retval = dblayer_txn_begin(be, parent_txn, &txn); } else { /* Otherwise, no SERIAL LOCK */ retval = dblayer_txn_begin_ext(li, parent_txn, &txn, PR_FALSE); } if (0 != retval) { if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1; ldap_result_code= LDAP_OPERATIONS_ERROR; goto error_return; } /* stash the transaction for plugins */ slapi_pblock_set(pb, SLAPI_TXN, txn.back_txn_txn); if (0 == retry_count) { /* just once */ if ( !MANAGE_ENTRY_BEFORE_DBLOCK(li)) { /* find and lock the entry we are about to modify */ if (fixup_tombstone) { e = find_entry2modify_only_ext( pb, be, addr, TOMBSTONE_INCLUDED, &txn, &result_sent ); } else { e = find_entry2modify( pb, be, addr, &txn, &result_sent ); } if (e == NULL) { ldap_result_code = -1; goto error_return; /* error result sent by find_entry2modify() */ } } if ( !is_fixup_operation && !fixup_tombstone) { if (!repl_op && slapi_entry_flag_is_set(e->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE)) { ldap_result_code = LDAP_UNWILLING_TO_PERFORM; ldap_result_message = "Operation not allowed on tombstone entry."; slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "Attempt to modify a tombstone entry %s\n", slapi_sdn_get_dn(slapi_entry_get_sdn_const( e->ep_entry ))); goto error_return; } opcsn = operation_get_csn (operation); if (NULL == opcsn && operation->o_csngen_handler) { /* * Current op is a user request. Opcsn will be assigned * if the dn is in an updatable replica. */ opcsn = entry_assign_operation_csn ( pb, e->ep_entry, NULL ); } if (opcsn) { entry_set_maxcsn (e->ep_entry, opcsn); } } /* Save away a copy of the entry, before modifications */ slapi_pblock_set( pb, SLAPI_ENTRY_PRE_OP, slapi_entry_dup( e->ep_entry )); if ( (ldap_result_code = plugin_call_acl_mods_access( pb, e->ep_entry, mods, &errbuf)) != LDAP_SUCCESS ) { ldap_result_message= errbuf; goto error_return; } /* create a copy of the entry and apply the changes to it */ if ( (ec = backentry_dup( e )) == NULL ) { ldap_result_code= LDAP_OPERATIONS_ERROR; goto error_return; } if(!repl_op){ remove_illegal_mods(mods); } /* ec is the entry that our bepreop should get to mess with */ slapi_pblock_set( pb, SLAPI_MODIFY_EXISTING_ENTRY, ec->ep_entry ); slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code); opreturn = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_MODIFY_FN); if (opreturn || (slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code) && ldap_result_code) || (slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn) && opreturn)) { slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn); if (!ldap_result_code) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "SLAPI_PLUGIN_BE_PRE_MODIFY_FN " "returned error but did not set SLAPI_RESULT_CODE\n"); ldap_result_code = LDAP_OPERATIONS_ERROR; } if (SLAPI_PLUGIN_NOOP == opreturn) { not_an_error = 1; rc = opreturn = LDAP_SUCCESS; } else if (!opreturn) { opreturn = SLAPI_PLUGIN_FAILURE; slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &opreturn); } slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message); goto error_return; } /* The Plugin may have messed about with some of the PBlock parameters... ie. mods */ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods ); /* apply the mods, check for syntax, schema problems, etc. */ if (modify_apply_check_expand(pb, operation, mods, e, ec, &postentry, &ldap_result_code, &ldap_result_message)) { goto error_return; } /* the schema check could have added a repl conflict mod * get the mods again */ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods ); slapi_mods_init_byref(&smods,mods); mod_count = slapi_mods_get_num_mods(&smods); /* * Grab a copy of the mods and the entry in case the be_txn_preop changes * the them. If we have a failure, then we need to reset the mods to their * their original state; */ mods_original = copy_mods(mods); if ( (original_entry = backentry_dup( ec )) == NULL ) { ldap_result_code= LDAP_OPERATIONS_ERROR; goto error_return; } } /* if (0 == retry_count) just once */ /* call the transaction pre modify plugins just after creating the transaction */ retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN); if (retval) { slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_modify", "SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN plugin " "returned error code %d\n", retval ); slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn); if (SLAPI_PLUGIN_NOOP == retval) { not_an_error = 1; rc = retval = LDAP_SUCCESS; } if (!opreturn) { slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval); } slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message); goto error_return; } /* the mods might have been changed, so get the latest */ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods ); /* make sure the betxnpreop did not alter any of the mods that had already previously been applied */ slapi_mods_done(&smods); slapi_mods_init_byref(&smods,mods); new_mod_count = slapi_mods_get_num_mods(&smods); if (new_mod_count < mod_count) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "Error: BE_TXN_PRE_MODIFY plugin has removed " "mods from the original list - mod count was [%d] now [%d] " "mods will not be applied - mods list changes must be done " "in the BE_PRE_MODIFY plugin, not the BE_TXN_PRE_MODIFY\n", mod_count, new_mod_count ); } else if (new_mod_count > mod_count) { /* apply the new betxnpremod mods */ /* apply the mods, check for syntax, schema problems, etc. */ if (modify_apply_check_expand(pb, operation, &mods[mod_count], e, ec, &postentry, &ldap_result_code, &ldap_result_message)) { goto error_return; } } /* else if new_mod_count == mod_count then betxnpremod plugin did nothing */ /* * Update the ID to Entry index. * Note that id2entry_add replaces the entry, so the Entry ID * stays the same. */ retval = id2entry_add_ext( be, ec, &txn, 1, &cache_rc ); if (DB_LOCK_DEADLOCK == retval) { /* Abort and re-try */ continue; } if (0 != retval) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "id2entry_add failed, err=%d %s\n", retval, (msg = dblayer_strerror( retval )) ? msg : ""); if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1; MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count); goto error_return; } retval = index_add_mods( be, mods, e, ec, &txn ); if (DB_LOCK_DEADLOCK == retval) { /* Abort and re-try */ continue; } if (0 != retval) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "index_add_mods failed, err=%d %s\n", retval, (msg = dblayer_strerror( retval )) ? msg : ""); if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1; MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count); goto error_return; } /* * Remove the old entry from the Virtual List View indexes. * Add the new entry to the Virtual List View indexes. * If the entry is ruv, no need to update vlv. */ if (!is_ruv) { retval= vlv_update_all_indexes(&txn, be, pb, e, ec); if (DB_LOCK_DEADLOCK == retval) { /* Abort and re-try */ continue; } if (0 != retval) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "vlv_update_index failed, err=%d %s\n", retval, (msg = dblayer_strerror( retval )) ? msg : ""); if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1; MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count); goto error_return; } } if (!is_ruv && !is_fixup_operation && !NO_RUV_UPDATE(li)) { ruv_c_init = ldbm_txn_ruv_modify_context( pb, &ruv_c ); if (-1 == ruv_c_init) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "ldbm_txn_ruv_modify_context failed to construct RUV modify context\n"); ldap_result_code= LDAP_OPERATIONS_ERROR; retval = 0; goto error_return; } } if (ruv_c_init) { retval = modify_update_all( be, pb, &ruv_c, &txn ); if (DB_LOCK_DEADLOCK == retval) { /* Abort and re-try */ continue; } if (0 != retval) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "modify_update_all failed, err=%d %s\n", retval, (msg = dblayer_strerror( retval )) ? msg : ""); if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1; ldap_result_code= LDAP_OPERATIONS_ERROR; goto error_return; } } if (0 == retval) { break; } } if (retry_count == RETRY_TIMES) { slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "Retry count exceeded in modify\n"); ldap_result_code= LDAP_BUSY; goto error_return; } if (ruv_c_init) { if (modify_switch_entries(&ruv_c, be) != 0 ) { ldap_result_code= LDAP_OPERATIONS_ERROR; slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", "modify_switch_entries failed\n"); goto error_return; } } if (cache_replace( &inst->inst_cache, e, ec ) != 0 ) { MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count); goto error_return; } /* e uncached */ /* we must return both e (which has been deleted) and new entry ec to cache */ /* cache_replace removes e from the cache hash tables */ cache_unlock_entry( &inst->inst_cache, e ); CACHE_RETURN( &inst->inst_cache, &e ); /* lock new entry in cache to prevent usage until we are complete */ cache_lock_entry( &inst->inst_cache, ec ); ec_locked = 1; postentry = slapi_entry_dup( ec->ep_entry ); slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, postentry ); /* invalidate virtual cache */ ec->ep_entry->e_virtual_watermark = 0; /* * LP Fix of crash when the commit will fail: * If the commit fail, the common error path will * try to unlock the entry again and crash (PR_ASSERT * in debug mode. * By just setting e to NULL, we avoid this. It's OK since * we don't use e after that in the normal case. */ e = NULL; /* call the transaction post modify plugins just before the commit */ if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN))) { slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_modify", "SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN plugin " "returned error code %d\n", retval ); if (!ldap_result_code) { slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); } if (!opreturn) { slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn); } if (!opreturn) { slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval); } slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message); goto error_return; } /* Release SERIAL LOCK */ retval = dblayer_txn_commit(be, &txn); /* after commit - txn is no longer valid - replace SLAPI_TXN with parent */ slapi_pblock_set(pb, SLAPI_TXN, parent_txn); if (0 != retval) { if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1; ldap_result_code= LDAP_OPERATIONS_ERROR; goto error_return; } rc= 0; goto common_return; error_return: if ( postentry != NULL ) { slapi_entry_free( postentry ); postentry = NULL; slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, NULL ); } if (retval == DB_RUNRECOVERY) { dblayer_remember_disk_filled(li); ldbm_nasty("ldbm_back_modify","Modify",81,retval); disk_full = 1; } if (disk_full) { rc= return_on_disk_full(li); } else { if (txn.back_txn_txn && (txn.back_txn_txn != parent_txn)) { /* make sure SLAPI_RESULT_CODE and SLAPI_PLUGIN_OPRETURN are set */ int val = 0; slapi_pblock_get(pb, SLAPI_RESULT_CODE, &val); if (!val) { if (!ldap_result_code) { ldap_result_code = LDAP_OPERATIONS_ERROR; } slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code); } slapi_pblock_get( pb, SLAPI_PLUGIN_OPRETURN, &val ); if (!val) { opreturn = -1; slapi_pblock_set( pb, SLAPI_PLUGIN_OPRETURN, &opreturn ); } /* call the transaction post modify plugins just before the abort */ /* plugins called before abort should check for the OPRETURN or RESULT_CODE and skip processing if they don't want do anything - some plugins that keep track of a counter (usn, dna) may want to "rollback" the counter in this case */ if ((retval = plugin_call_plugins(pb, SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN))) { slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_modify", "SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN plugin returned error code %d\n", retval ); slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code); slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message); slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &opreturn); if (!opreturn) { slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval); } } /* It is safer not to abort when the transaction is not started. */ /* Release SERIAL LOCK */ dblayer_txn_abort(be, &txn); /* abort crashes in case disk full */ /* txn is no longer valid - reset the txn pointer to the parent */ slapi_pblock_set(pb, SLAPI_TXN, parent_txn); } if (!not_an_error) { rc = SLAPI_FAIL_GENERAL; } } /* if ec is in cache, remove it, then add back e if we still have it */ if (inst && cache_is_in_cache(&inst->inst_cache, ec)) { CACHE_REMOVE( &inst->inst_cache, ec ); /* if ec was in cache, e was not - add back e */ if (e) { if (CACHE_ADD( &inst->inst_cache, e, NULL ) < 0) { slapi_log_err(SLAPI_LOG_CACHE, "ldbm_back_modify", "CACHE_ADD %s failed\n", slapi_entry_get_dn(e->ep_entry)); } } } common_return: slapi_mods_done(&smods); if (inst) { if (ec_locked || cache_is_in_cache(&inst->inst_cache, ec)) { cache_unlock_entry(&inst->inst_cache, ec); } else if (e) { /* if ec was not in cache, cache_replace was not done. * i.e., e was not unlocked. */ cache_unlock_entry(&inst->inst_cache, e); CACHE_RETURN(&inst->inst_cache, &e); } CACHE_RETURN(&inst->inst_cache, &ec); if (inst->inst_ref_count) { slapi_counter_decrement(inst->inst_ref_count); } } /* result code could be used in the bepost plugin functions. */ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code); /* The bepostop is called even if the operation fails. */ if (!disk_full) plugin_call_plugins (pb, SLAPI_PLUGIN_BE_POST_MODIFY_FN); if (ruv_c_init) { modify_term(&ruv_c, be); } if (ldap_result_code == -1) { /* Reset to LDAP_NO_SUCH_OBJECT*/ ldap_result_code = LDAP_NO_SUCH_OBJECT; slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code); } else { if (not_an_error) { /* This is mainly used by urp. Solved conflict is not an error. * And we don't want the supplier to halt sending the updates. */ ldap_result_code = LDAP_SUCCESS; } if (!result_sent) { /* result is already sent in find_entry. */ slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL ); } } /* free our backups */ ldap_mods_free(mods_original, 1); backentry_free(&original_entry); backentry_free(&tmpentry); slapi_ch_free_string(&errbuf); return rc; }
/* * Common function that is called by aclplugin_preop_search() and * aclplugin_preop_modify(). * * Return values: * 0 - all is well; proceed. * 1 - fatal error; result has been sent to client. */ int aclplugin_preop_common( Slapi_PBlock *pb ) { char *proxy_dn = NULL; /* id being assumed */ char *dn; /* proxy master */ char *errtext = NULL; int lderr; Acl_PBlock *aclpb; TNF_PROBE_0_DEBUG(aclplugin_preop_common_start ,"ACL",""); aclpb = acl_get_aclpb ( pb, ACLPB_BINDDN_PBLOCK ); if (aclpb == NULL) { slapi_log_err(SLAPI_LOG_ACL, plugin_name, "aclplugin_preop_common - Error: aclpb is NULL\n" ); slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL ); return 1; } /* See if we have initialized already */ if ( aclpb->aclpb_state & ACLPB_INITIALIZED ) goto done; /* * The following mallocs memory for proxy_dn, but not the dn. * The proxy_dn is the id being assumed, while dn * is the "proxy master". */ if ( LDAP_SUCCESS != ( lderr = proxyauth_get_dn( pb, &proxy_dn, &errtext ))) { /* * Fatal error -- send a result to the client and arrange to skip * any further processing. */ slapi_send_ldap_result( pb, lderr, NULL, errtext, 0, NULL ); TNF_PROBE_1_DEBUG(aclplugin_preop_common_end ,"ACL","", tnf_string,proxid_error,""); slapi_ch_free_string(&proxy_dn); return 1; /* skip any further processing */ } slapi_pblock_get ( pb, SLAPI_REQUESTOR_DN, &dn ); /* * The dn is copied into the aclpb during initialization. */ if ( proxy_dn) { TNF_PROBE_0_DEBUG(proxyacpb_init_start,"ACL",""); slapi_log_err(SLAPI_LOG_ACL, plugin_name, "aclplugin_preop_common - Proxied authorization dn is (%s)\n", proxy_dn ); acl_init_aclpb ( pb, aclpb, proxy_dn, 1 ); aclpb = acl_new_proxy_aclpb ( pb ); acl_init_aclpb ( pb, aclpb, dn, 0 ); slapi_ch_free ( (void **) &proxy_dn ); TNF_PROBE_0_DEBUG(proxyacpb_init_end,"ACL",""); } else { TNF_PROBE_0_DEBUG(aclpb_init_start,"ACL",""); acl_init_aclpb ( pb, aclpb, dn, 1 ); TNF_PROBE_0_DEBUG(aclpb_init_end,"ACL",""); } done: TNF_PROBE_0_DEBUG(aclplugin_preop_common_end ,"ACL",""); return 0; }
/* * Do the actual work of authenticating with PAM. First, get the PAM identity * based on the method used to convert the BIND identity to the PAM identity. * Set up the structures that pam_start needs and call pam_start(). After * that, call pam_authenticate and pam_acct_mgmt. Check the various return * values from these functions and map them to their corresponding LDAP BIND * return values. Return the appropriate LDAP error code. * This function will also set the appropriate LDAP response controls in * the given pblock. * Since this function can be called multiple times, we only want to return * the errors and controls to the user if this is the final call, so the * final_method parameter tells us if this is the last one. Coupled with * the fallback argument, we can tell if we are able to send the response * back to the client. */ static int do_one_pam_auth( Slapi_PBlock *pb, int method, /* get pam identity from ENTRY, RDN, or DN */ PRBool final_method, /* which method is the last one to try */ char *pam_service, /* name of service for pam_start() */ char *map_ident_attr, /* for ENTRY method, name of attribute holding pam identity */ PRBool fallback, /* if true, failure here should fallback to regular bind */ int pw_response_requested /* do we need to send pwd policy resp control */ ) { MyStrBuf pam_id; const char *binddn = NULL; Slapi_DN *bindsdn = NULL; int rc; int retcode = LDAP_SUCCESS; pam_handle_t *pam_handle; struct my_pam_conv_str my_data; struct pam_conv my_pam_conv = {pam_conv_func, NULL}; char *errmsg = NULL; /* free with PR_smprintf_free */ int locked = 0; slapi_pblock_get( pb, SLAPI_BIND_TARGET_SDN, &bindsdn ); if (NULL == bindsdn) { errmsg = PR_smprintf("Null bind dn"); retcode = LDAP_OPERATIONS_ERROR; pam_id.str = NULL; /* initialize pam_id.str */ goto done; /* skip the pam stuff */ } binddn = slapi_sdn_get_dn(bindsdn); if (method == PAMPT_MAP_METHOD_RDN) { derive_from_bind_dn(pb, bindsdn, &pam_id); } else if (method == PAMPT_MAP_METHOD_ENTRY) { derive_from_bind_entry(pb, bindsdn, &pam_id, map_ident_attr, &locked); } else { init_my_str_buf(&pam_id, binddn); } if (locked) { errmsg = PR_smprintf("Account inactivated. Contact system administrator."); retcode = LDAP_UNWILLING_TO_PERFORM; /* user inactivated */ goto done; /* skip the pam stuff */ } if (!pam_id.str) { errmsg = PR_smprintf("Bind DN [%s] is invalid or not found", binddn); retcode = LDAP_NO_SUCH_OBJECT; /* user unknown */ goto done; /* skip the pam stuff */ } /* do the pam stuff */ my_data.pb = pb; my_data.pam_identity = pam_id.str; my_pam_conv.appdata_ptr = &my_data; slapi_lock_mutex(PAMLock); /* from this point on we are in the critical section */ rc = pam_start(pam_service, pam_id.str, &my_pam_conv, &pam_handle); report_pam_error("during pam_start", rc, pam_handle); if (rc == PAM_SUCCESS) { /* use PAM_SILENT - there is no user interaction at this point */ rc = pam_authenticate(pam_handle, 0); report_pam_error("during pam_authenticate", rc, pam_handle); /* check different types of errors here */ if (rc == PAM_USER_UNKNOWN) { errmsg = PR_smprintf("User id [%s] for bind DN [%s] does not exist in PAM", pam_id.str, binddn); retcode = LDAP_NO_SUCH_OBJECT; /* user unknown */ } else if (rc == PAM_AUTH_ERR) { errmsg = PR_smprintf("Invalid PAM password for user id [%s], bind DN [%s]", pam_id.str, binddn); retcode = LDAP_INVALID_CREDENTIALS; /* invalid creds */ } else if (rc == PAM_MAXTRIES) { errmsg = PR_smprintf("Authentication retry limit exceeded in PAM for " "user id [%s], bind DN [%s]", pam_id.str, binddn); if (pw_response_requested) { slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_ACCTLOCKED); } retcode = LDAP_CONSTRAINT_VIOLATION; /* max retries */ } else if (rc != PAM_SUCCESS) { errmsg = PR_smprintf("Unknown PAM error [%s] for user id [%s], bind DN [%s]", pam_strerror(pam_handle, rc), pam_id.str, binddn); retcode = LDAP_OPERATIONS_ERROR; /* pam config or network problem */ } } /* if user authenticated successfully, see if there is anything we need to report back w.r.t. password or account lockout */ if (rc == PAM_SUCCESS) { rc = pam_acct_mgmt(pam_handle, 0); report_pam_error("during pam_acct_mgmt", rc, pam_handle); /* check different types of errors here */ if (rc == PAM_USER_UNKNOWN) { errmsg = PR_smprintf("User id [%s] for bind DN [%s] does not exist in PAM", pam_id.str, binddn); retcode = LDAP_NO_SUCH_OBJECT; /* user unknown */ } else if (rc == PAM_AUTH_ERR) { errmsg = PR_smprintf("Invalid PAM password for user id [%s], bind DN [%s]", pam_id.str, binddn); retcode = LDAP_INVALID_CREDENTIALS; /* invalid creds */ } else if (rc == PAM_PERM_DENIED) { errmsg = PR_smprintf("Access denied for PAM user id [%s], bind DN [%s]" " - see administrator", pam_id.str, binddn); if (pw_response_requested) { slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_ACCTLOCKED); } retcode = LDAP_UNWILLING_TO_PERFORM; } else if (rc == PAM_ACCT_EXPIRED) { errmsg = PR_smprintf("Expired PAM password for user id [%s], bind DN [%s]: " "reset required", pam_id.str, binddn); slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0); if (pw_response_requested) { slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_PWDEXPIRED); } retcode = LDAP_INVALID_CREDENTIALS; } else if (rc == PAM_NEW_AUTHTOK_REQD) { /* handled same way as ACCT_EXPIRED */ errmsg = PR_smprintf("Expired PAM password for user id [%s], bind DN [%s]: " "reset required", pam_id.str, binddn); slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0); if (pw_response_requested) { slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_PWDEXPIRED); } retcode = LDAP_INVALID_CREDENTIALS; } else if (rc != PAM_SUCCESS) { errmsg = PR_smprintf("Unknown PAM error [%s] for user id [%s], bind DN [%s]", pam_strerror(pam_handle, rc), pam_id.str, binddn); retcode = LDAP_OPERATIONS_ERROR; /* unknown */ } } rc = pam_end(pam_handle, rc); report_pam_error("during pam_end", rc, pam_handle); slapi_unlock_mutex(PAMLock); /* not in critical section any more */ done: delete_my_str_buf(&pam_id); if ((retcode == LDAP_SUCCESS) && (rc != PAM_SUCCESS)) { errmsg = PR_smprintf("Unknown PAM error [%d] for user id [%s], bind DN [%s]", rc, pam_id.str, binddn); retcode = LDAP_OPERATIONS_ERROR; } if (retcode != LDAP_SUCCESS) { slapi_log_error(SLAPI_LOG_FATAL, PAM_PASSTHRU_PLUGIN_SUBSYSTEM, "%s\n", errmsg); if (final_method && !fallback) { slapi_send_ldap_result(pb, retcode, NULL, errmsg, 0, NULL); } } if (errmsg) { PR_smprintf_free(errmsg); } return retcode; }