4.1.28.3 Server Behavior of the IDL_DRSWriteSPN Method
Informative summary of behavior: The IDL_DRSWriteSPN method updates the servicePrincipalName attribute of an object. The values of this multivalued attribute are called service principal names (SPNs). The IDL_DRSWriteSPN method does one of three things:
Adds a non-empty set of SPNs to the object's servicePrincipalName. If a member of the set is already present on the object's servicePrincipalName, it is ignored.
Removes all current values from the object's servicePrincipalName, then adds a (possibly empty) set of SPNs to the object's servicePrincipalName.
Removes a non-empty set of SPNs from the object's servicePrincipalName. If a member of the set is not present on the object's servicePrincipalName, it is ignored.
The effect of this method can be achieved by an LDAP Modify operation to the servicePrincipalName attribute of an object. Some manipulations of the servicePrincipalName attribute that cannot be performed using this method can be performed using LDAP Modify. For example, an LDAP Modify can remove one specific SPN from the servicePrincipalName attribute while adding another SPN to the servicePrincipalName attribute in the same transaction; IDL_DRSWriteSPN cannot do this.
-
ULONG IDL_DRSWriteSPN( [in, ref] DRS_HANDLE hDrs, [in] DWORD dwInVersion, [in, ref, switch_is(dwInVersion)] DRS_MSG_SPNREQ *pmsgIn, [out, ref] DWORD *pdwOutVersion, [out, ref, switch_is(*pdwOutVersion)] DRS_MSG_SPNREPLY *pmsgOut); accountDN: unicodestring account: DSName err: DWORD operation: DS_SPN_OPERATION cSPN: integer spnSet: set of unicodestring instanceName: unicodestring ValidateDRSInput(hDrs, 13) pdwOutVersion^ := 1 pmsgOut^.V1.retVal := 0 /* Input parameter validation */ if dwInVersion ≠ 1 then pmsgOut^.V1.retVal := ERROR_INVALID_PARAMETER return ERROR_INVALID_PARAMETER endif /* Input parameter validation */ if ClientUUID(hDrs) ≠ NTDSAPI_CLIENT_GUID pmsgOut^.V1.retVal := ERROR_INVALID_PARAMETER return ERROR_INVALID_PARAMETER endif /* RODCs do not perform originating updates */ if AmIRODC() then return ExecuteWriteSPNRemotely(dwInVersion, pmsgIn, pdwOutVersion, pmsgOut); endif accountDN := pmsgIn^.V1.pwszAccount operation := pmsgIn^.V1.operation cSPN := pmsgIn^.V1.cSPN spnSet := pmsgIn^.V1.rpwszSPN if accountDN = null or accountDN = "" then pmsgOut^.V1.retVal := ERROR_INVALID_PARAMETER return ERROR_INVALID_PARAMETER endif if not operation in [DS_SPN_ADD_SPN_OP .. DS_SPN_DELETE_SPN_OP] then pmsgOut^.V1.retVal := ERROR_INVALID_FUNCTION return ERROR_INVALID_FUNCTION endif /* DS_SPN_REPLACE_SPN_OP permits 0 SPNs to be specified (meaning * "delete all SPNs"). Other operations require >=1 SPNs to be * specified. */ if (operation ≠ DS_SPN_REPLACE_SPN_OP) and (cSPN = 0) then pmsgOut^.V1.retVal := ERROR_INVALID_PARAMETER return ERROR_INVALID_PARAMETER endif /* The empty string is an invalid SPN. */ foreach spn in spnSet if spn = null or spn = "" then pmsgOut^.V1.retVal := ERROR_INVALID_PARAMETER return ERROR_INVALID_PARAMETER endif endfor account := GetDSNameFromDN(accountDN); if not ObjExists(account) then pmsgOut^.V1.retVal := ERROR_DS_OBJ_NOT_FOUND return ERROR_DS_OBJ_NOT_FOUND endif /* Perform access checks */ err = AccessCheckWriteToSpnAttribute(account, spnSet) if err ≠ ERROR_SUCCESS then pmsgOut^.V1.retVal := err return err endif if (operation = DS_SPN_DELETE_SPN_OP) then /* Remove specified SPNs */ foreach spn in spnSet if spn in account!servicePrincipalName then account!servicePrincipalName := account!servicePrincipalName - {spn} endif endfor return 0 endif if (operation = DS_SPN_ADD_SPN_OP) then /* Add specified SPNs */ foreach spn in spnSet account!servicePrincipalName := account!servicePrincipalName + {spn} endfor return 0 endif /* Must be DS_SPN_REPLACE_SPN_OP. * Remove all existing SPNs, then add in the specified SPNs. */ account!servicePrincipalName := {null} foreach spn in spnSet account!servicePrincipalName := account!servicePrincipalName + {spn} endfor return 0