s3/docs: Fix typo.
[Samba/gebeck_regimport.git] / source3 / rpc_server / srv_eventlog_nt.c
blob7143ad62678220571718af4a3c2084f372f934b7
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Marcin Krzysztof Porwit 2005,
5 * Copyright (C) Brian Moran 2005,
6 * Copyright (C) Gerald (Jerry) Carter 2005.
7 * Copyright (C) Guenther Deschner 2009.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
25 #undef DBGC_CLASS
26 #define DBGC_CLASS DBGC_RPC_SRV
28 typedef struct {
29 char *logname;
30 ELOG_TDB *etdb;
31 uint32 current_record;
32 uint32 num_records;
33 uint32 oldest_entry;
34 uint32 flags;
35 uint32 access_granted;
36 } EVENTLOG_INFO;
38 /********************************************************************
39 ********************************************************************/
41 static int eventlog_info_destructor(EVENTLOG_INFO *elog)
43 if (elog->etdb) {
44 elog_close_tdb(elog->etdb, false);
46 return 0;
49 /********************************************************************
50 ********************************************************************/
52 static EVENTLOG_INFO *find_eventlog_info_by_hnd( pipes_struct * p,
53 struct policy_handle * handle )
55 EVENTLOG_INFO *info;
57 if ( !find_policy_by_hnd( p, handle, (void **)(void *)&info ) ) {
58 DEBUG( 2,
59 ( "find_eventlog_info_by_hnd: eventlog not found.\n" ) );
60 return NULL;
63 return info;
66 /********************************************************************
67 ********************************************************************/
69 static bool elog_check_access( EVENTLOG_INFO *info, NT_USER_TOKEN *token )
71 char *tdbname = elog_tdbname(talloc_tos(), info->logname );
72 SEC_DESC *sec_desc;
73 NTSTATUS status;
75 if ( !tdbname )
76 return False;
78 /* get the security descriptor for the file */
80 sec_desc = get_nt_acl_no_snum( info, tdbname );
81 TALLOC_FREE( tdbname );
83 if ( !sec_desc ) {
84 DEBUG(5,("elog_check_access: Unable to get NT ACL for %s\n",
85 tdbname));
86 return False;
89 /* root free pass */
91 if ( geteuid() == sec_initial_uid() ) {
92 DEBUG(5,("elog_check_access: using root's token\n"));
93 token = get_root_nt_token();
96 /* run the check, try for the max allowed */
98 status = se_access_check( sec_desc, token, MAXIMUM_ALLOWED_ACCESS,
99 &info->access_granted);
101 if ( sec_desc )
102 TALLOC_FREE( sec_desc );
104 if (!NT_STATUS_IS_OK(status)) {
105 DEBUG(8,("elog_check_access: se_access_check() return %s\n",
106 nt_errstr(status)));
107 return False;
110 /* we have to have READ permission for a successful open */
112 return ( info->access_granted & SA_RIGHT_FILE_READ_DATA );
115 /********************************************************************
116 ********************************************************************/
118 static bool elog_validate_logname( const char *name )
120 int i;
121 const char **elogs = lp_eventlog_list();
123 if (!elogs) {
124 return False;
127 for ( i=0; elogs[i]; i++ ) {
128 if ( strequal( name, elogs[i] ) )
129 return True;
132 return False;
135 /********************************************************************
136 ********************************************************************/
138 static bool get_num_records_hook( EVENTLOG_INFO * info )
140 int next_record;
141 int oldest_record;
143 if ( !info->etdb ) {
144 DEBUG( 10, ( "No open tdb for %s\n", info->logname ) );
145 return False;
148 /* lock the tdb since we have to get 2 records */
150 tdb_lock_bystring_with_timeout( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD, 1 );
151 next_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
152 oldest_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_OLDEST_ENTRY);
153 tdb_unlock_bystring( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD);
155 DEBUG( 8,
156 ( "Oldest Record %d; Next Record %d\n", oldest_record,
157 next_record ) );
159 info->num_records = ( next_record - oldest_record );
160 info->oldest_entry = oldest_record;
162 return True;
165 /********************************************************************
166 ********************************************************************/
168 static bool get_oldest_entry_hook( EVENTLOG_INFO * info )
170 /* it's the same thing */
171 return get_num_records_hook( info );
174 /********************************************************************
175 ********************************************************************/
177 static NTSTATUS elog_open( pipes_struct * p, const char *logname, struct policy_handle *hnd )
179 EVENTLOG_INFO *elog;
181 /* first thing is to validate the eventlog name */
183 if ( !elog_validate_logname( logname ) )
184 return NT_STATUS_OBJECT_PATH_INVALID;
186 if ( !(elog = TALLOC_ZERO_P( NULL, EVENTLOG_INFO )) )
187 return NT_STATUS_NO_MEMORY;
188 talloc_set_destructor(elog, eventlog_info_destructor);
190 elog->logname = talloc_strdup( elog, logname );
192 /* Open the tdb first (so that we can create any new tdbs if necessary).
193 We have to do this as root and then use an internal access check
194 on the file permissions since you can only have a tdb open once
195 in a single process */
197 become_root();
198 elog->etdb = elog_open_tdb( elog->logname, False, False );
199 unbecome_root();
201 if ( !elog->etdb ) {
202 /* according to MSDN, if the logfile cannot be found, we should
203 default to the "Application" log */
205 if ( !strequal( logname, ELOG_APPL ) ) {
207 TALLOC_FREE( elog->logname );
209 elog->logname = talloc_strdup( elog, ELOG_APPL );
211 /* do the access check */
212 if ( !elog_check_access( elog, p->server_info->ptok ) ) {
213 TALLOC_FREE( elog );
214 return NT_STATUS_ACCESS_DENIED;
217 become_root();
218 elog->etdb = elog_open_tdb( elog->logname, False, False );
219 unbecome_root();
222 if ( !elog->etdb ) {
223 TALLOC_FREE( elog );
224 return NT_STATUS_ACCESS_DENIED; /* ??? */
228 /* now do the access check. Close the tdb if we fail here */
230 if ( !elog_check_access( elog, p->server_info->ptok ) ) {
231 TALLOC_FREE( elog );
232 return NT_STATUS_ACCESS_DENIED;
235 /* create the policy handle */
237 if ( !create_policy_hnd( p, hnd, elog ) ) {
238 TALLOC_FREE(elog);
239 return NT_STATUS_NO_MEMORY;
242 /* set the initial current_record pointer */
244 if ( !get_oldest_entry_hook( elog ) ) {
245 DEBUG(3,("elog_open: Successfully opened eventlog but can't "
246 "get any information on internal records!\n"));
249 elog->current_record = elog->oldest_entry;
251 return NT_STATUS_OK;
254 /********************************************************************
255 ********************************************************************/
257 static NTSTATUS elog_close( pipes_struct *p, struct policy_handle *hnd )
259 if ( !( close_policy_hnd( p, hnd ) ) ) {
260 return NT_STATUS_INVALID_HANDLE;
263 return NT_STATUS_OK;
266 /*******************************************************************
267 *******************************************************************/
269 static int elog_size( EVENTLOG_INFO *info )
271 if ( !info || !info->etdb ) {
272 DEBUG(0,("elog_size: Invalid info* structure!\n"));
273 return 0;
276 return elog_tdb_size( ELOG_TDB_CTX(info->etdb), NULL, NULL );
279 /********************************************************************
280 note that this can only be called AFTER the table is constructed,
281 since it uses the table to find the tdb handle
282 ********************************************************************/
284 static bool sync_eventlog_params( EVENTLOG_INFO *info )
286 char *path = NULL;
287 uint32 uiMaxSize;
288 uint32 uiRetention;
289 struct registry_key *key;
290 struct registry_value *value;
291 WERROR wresult;
292 char *elogname = info->logname;
293 TALLOC_CTX *ctx = talloc_stackframe();
294 bool ret = false;
296 DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) );
298 if ( !info->etdb ) {
299 DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) );
300 goto done;
302 /* set resonable defaults. 512Kb on size and 1 week on time */
304 uiMaxSize = 0x80000;
305 uiRetention = 604800;
307 /* the general idea is to internally open the registry
308 key and retrieve the values. That way we can continue
309 to use the same fetch/store api that we use in
310 srv_reg_nt.c */
312 path = talloc_asprintf(ctx, "%s/%s", KEY_EVENTLOG, elogname );
313 if (!path) {
314 goto done;
317 wresult = reg_open_path(ctx, path, REG_KEY_READ, get_root_nt_token(),
318 &key);
320 if ( !W_ERROR_IS_OK( wresult ) ) {
321 DEBUG( 4,
322 ( "sync_eventlog_params: Failed to open key [%s] (%s)\n",
323 path, win_errstr( wresult ) ) );
324 goto done;
327 wresult = reg_queryvalue(key, key, "Retention", &value);
328 if (!W_ERROR_IS_OK(wresult)) {
329 DEBUG(4, ("Failed to query value \"Retention\": %s\n",
330 win_errstr(wresult)));
331 goto done;
333 uiRetention = value->v.dword;
335 wresult = reg_queryvalue(key, key, "MaxSize", &value);
336 if (!W_ERROR_IS_OK(wresult)) {
337 DEBUG(4, ("Failed to query value \"MaxSize\": %s\n",
338 win_errstr(wresult)));
339 goto done;
341 uiMaxSize = value->v.dword;
343 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize );
344 tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention );
346 ret = true;
348 done:
349 TALLOC_FREE(ctx);
350 return ret;
353 /********************************************************************
354 _eventlog_OpenEventLogW
355 ********************************************************************/
357 NTSTATUS _eventlog_OpenEventLogW(pipes_struct *p,
358 struct eventlog_OpenEventLogW *r)
360 EVENTLOG_INFO *info;
361 NTSTATUS result;
363 DEBUG( 10,("_eventlog_OpenEventLogW: Server [%s], Log [%s]\n",
364 r->in.servername->string, r->in.logname->string ));
366 /* according to MSDN, if the logfile cannot be found, we should
367 default to the "Application" log */
369 if ( !NT_STATUS_IS_OK( result = elog_open( p, r->in.logname->string, r->out.handle )) )
370 return result;
372 if ( !(info = find_eventlog_info_by_hnd( p, r->out.handle )) ) {
373 DEBUG(0,("_eventlog_OpenEventLogW: eventlog (%s) opened but unable to find handle!\n",
374 r->in.logname->string ));
375 elog_close( p, r->out.handle );
376 return NT_STATUS_INVALID_HANDLE;
379 DEBUG(10,("_eventlog_OpenEventLogW: Size [%d]\n", elog_size( info )));
381 sync_eventlog_params( info );
382 prune_eventlog( ELOG_TDB_CTX(info->etdb) );
384 return NT_STATUS_OK;
387 /********************************************************************
388 _eventlog_ClearEventLogW
389 This call still needs some work
390 ********************************************************************/
391 /** The windows client seems to be doing something funny with the file name
392 A call like
393 ClearEventLog(handle, "backup_file")
394 on the client side will result in the backup file name looking like this on the
395 server side:
396 \??\${CWD of client}\backup_file
397 If an absolute path gets specified, such as
398 ClearEventLog(handle, "C:\\temp\\backup_file")
399 then it is still mangled by the client into this:
400 \??\C:\temp\backup_file
401 when it is on the wire.
402 I'm not sure where the \?? is coming from, or why the ${CWD} of the client process
403 would be added in given that the backup file gets written on the server side. */
405 NTSTATUS _eventlog_ClearEventLogW(pipes_struct *p,
406 struct eventlog_ClearEventLogW *r)
408 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
410 if ( !info )
411 return NT_STATUS_INVALID_HANDLE;
413 if (r->in.backupfile && r->in.backupfile->string) {
415 DEBUG(8,( "_eventlog_ClearEventLogW: Using [%s] as the backup "
416 "file name for log [%s].",
417 r->in.backupfile->string, info->logname ) );
420 /* check for WRITE access to the file */
422 if ( !(info->access_granted&SA_RIGHT_FILE_WRITE_DATA) )
423 return NT_STATUS_ACCESS_DENIED;
425 /* Force a close and reopen */
427 elog_close_tdb( info->etdb, True );
428 become_root();
429 info->etdb = elog_open_tdb( info->logname, True, False );
430 unbecome_root();
432 if ( !info->etdb )
433 return NT_STATUS_ACCESS_DENIED;
435 return NT_STATUS_OK;
438 /********************************************************************
439 _eventlog_CloseEventLog
440 ********************************************************************/
442 NTSTATUS _eventlog_CloseEventLog(pipes_struct * p,
443 struct eventlog_CloseEventLog *r)
445 NTSTATUS status;
447 status = elog_close( p, r->in.handle );
448 if (!NT_STATUS_IS_OK(status)) {
449 return status;
452 ZERO_STRUCTP(r->out.handle);
454 return NT_STATUS_OK;
457 /********************************************************************
458 _eventlog_ReadEventLogW
459 ********************************************************************/
461 NTSTATUS _eventlog_ReadEventLogW(pipes_struct *p,
462 struct eventlog_ReadEventLogW *r)
464 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
465 uint32_t num_records_read = 0;
466 int bytes_left, record_number;
467 uint32_t elog_read_type, elog_read_dir;
469 if (!info) {
470 return NT_STATUS_INVALID_HANDLE;
473 info->flags = r->in.flags;
474 bytes_left = r->in.number_of_bytes;
476 if (!info->etdb) {
477 return NT_STATUS_ACCESS_DENIED;
480 /* check for valid flags. Can't use the sequential and seek flags together */
482 elog_read_type = r->in.flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ);
483 elog_read_dir = r->in.flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ);
485 if (r->in.flags == 0 ||
486 elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ) ||
487 elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ))
489 DEBUG(3,("_eventlog_ReadEventLogW: "
490 "Invalid flags [0x%08x] for ReadEventLog\n",
491 r->in.flags));
492 return NT_STATUS_INVALID_PARAMETER;
495 /* a sequential read should ignore the offset */
497 if (elog_read_type & EVENTLOG_SEQUENTIAL_READ) {
498 record_number = info->current_record;
499 } else {
500 record_number = r->in.offset;
503 if (r->in.number_of_bytes == 0) {
504 struct EVENTLOGRECORD *e;
505 e = evlog_pull_record(p->mem_ctx, ELOG_TDB_CTX(info->etdb),
506 record_number);
507 if (!e) {
508 return NT_STATUS_END_OF_FILE;
510 *r->out.real_size = e->Length;
511 return NT_STATUS_BUFFER_TOO_SMALL;
514 while (bytes_left > 0) {
516 DATA_BLOB blob;
517 enum ndr_err_code ndr_err;
518 struct EVENTLOGRECORD *e;
520 e = evlog_pull_record(p->mem_ctx, ELOG_TDB_CTX(info->etdb),
521 record_number);
522 if (!e) {
523 break;
526 ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, NULL, e,
527 (ndr_push_flags_fn_t)ndr_push_EVENTLOGRECORD);
528 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
529 return ndr_map_error2ntstatus(ndr_err);
532 if (DEBUGLEVEL >= 10) {
533 NDR_PRINT_DEBUG(EVENTLOGRECORD, e);
536 if (blob.length > r->in.number_of_bytes) {
537 *r->out.real_size = blob.length;
538 return NT_STATUS_BUFFER_TOO_SMALL;
541 if (*r->out.sent_size + blob.length > r->in.number_of_bytes) {
542 break;
545 bytes_left -= blob.length;
547 if (info->flags & EVENTLOG_FORWARDS_READ) {
548 record_number++;
549 } else {
550 record_number--;
553 /* update the eventlog record pointer */
555 info->current_record = record_number;
557 memcpy(&r->out.data[*(r->out.sent_size)],
558 blob.data, blob.length);
559 *(r->out.sent_size) += blob.length;
561 num_records_read++;
564 if (r->in.offset == 0 && record_number == 0 && *r->out.sent_size == 0) {
565 return NT_STATUS_END_OF_FILE;
568 return NT_STATUS_OK;
571 /********************************************************************
572 _eventlog_GetOldestRecord
573 ********************************************************************/
575 NTSTATUS _eventlog_GetOldestRecord(pipes_struct *p,
576 struct eventlog_GetOldestRecord *r)
578 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
580 if (info == NULL) {
581 return NT_STATUS_INVALID_HANDLE;
584 if ( !( get_oldest_entry_hook( info ) ) )
585 return NT_STATUS_ACCESS_DENIED;
587 *r->out.oldest_entry = info->oldest_entry;
589 return NT_STATUS_OK;
592 /********************************************************************
593 _eventlog_GetNumRecords
594 ********************************************************************/
596 NTSTATUS _eventlog_GetNumRecords(pipes_struct *p,
597 struct eventlog_GetNumRecords *r)
599 EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle );
601 if (info == NULL) {
602 return NT_STATUS_INVALID_HANDLE;
605 if ( !( get_num_records_hook( info ) ) )
606 return NT_STATUS_ACCESS_DENIED;
608 *r->out.number = info->num_records;
610 return NT_STATUS_OK;
613 NTSTATUS _eventlog_BackupEventLogW(pipes_struct *p, struct eventlog_BackupEventLogW *r)
615 p->rng_fault_state = True;
616 return NT_STATUS_NOT_IMPLEMENTED;
619 /********************************************************************
620 _eventlog_GetLogInformation
621 ********************************************************************/
623 NTSTATUS _eventlog_GetLogInformation(pipes_struct *p,
624 struct eventlog_GetLogInformation *r)
626 EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle);
627 struct EVENTLOG_FULL_INFORMATION f;
628 enum ndr_err_code ndr_err;
629 DATA_BLOB blob;
631 if (!info) {
632 return NT_STATUS_INVALID_HANDLE;
635 if (r->in.level != 0) {
636 return NT_STATUS_INVALID_LEVEL;
639 *r->out.bytes_needed = 4;
641 if (r->in.buf_size < 4) {
642 return NT_STATUS_BUFFER_TOO_SMALL;
645 /* FIXME: this should be retrieved from the handle */
646 f.full = false;
648 ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, NULL, &f,
649 (ndr_push_flags_fn_t)ndr_push_EVENTLOG_FULL_INFORMATION);
650 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
651 return ndr_map_error2ntstatus(ndr_err);
654 if (DEBUGLEVEL >= 10) {
655 NDR_PRINT_DEBUG(EVENTLOG_FULL_INFORMATION, &f);
658 memcpy(r->out.buffer, blob.data, 4);
660 return NT_STATUS_OK;
663 /********************************************************************
664 _eventlog_FlushEventLog
665 ********************************************************************/
667 NTSTATUS _eventlog_FlushEventLog(pipes_struct *p,
668 struct eventlog_FlushEventLog *r)
670 EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle);
671 if (!info) {
672 return NT_STATUS_INVALID_HANDLE;
675 return NT_STATUS_ACCESS_DENIED;
678 NTSTATUS _eventlog_DeregisterEventSource(pipes_struct *p, struct eventlog_DeregisterEventSource *r)
680 p->rng_fault_state = True;
681 return NT_STATUS_NOT_IMPLEMENTED;
684 NTSTATUS _eventlog_ChangeNotify(pipes_struct *p, struct eventlog_ChangeNotify *r)
686 p->rng_fault_state = True;
687 return NT_STATUS_NOT_IMPLEMENTED;
690 NTSTATUS _eventlog_RegisterEventSourceW(pipes_struct *p, struct eventlog_RegisterEventSourceW *r)
692 p->rng_fault_state = True;
693 return NT_STATUS_NOT_IMPLEMENTED;
696 NTSTATUS _eventlog_OpenBackupEventLogW(pipes_struct *p, struct eventlog_OpenBackupEventLogW *r)
698 p->rng_fault_state = True;
699 return NT_STATUS_NOT_IMPLEMENTED;
702 NTSTATUS _eventlog_ReportEventW(pipes_struct *p, struct eventlog_ReportEventW *r)
704 p->rng_fault_state = True;
705 return NT_STATUS_NOT_IMPLEMENTED;
708 NTSTATUS _eventlog_ClearEventLogA(pipes_struct *p, struct eventlog_ClearEventLogA *r)
710 p->rng_fault_state = True;
711 return NT_STATUS_NOT_IMPLEMENTED;
714 NTSTATUS _eventlog_BackupEventLogA(pipes_struct *p, struct eventlog_BackupEventLogA *r)
716 p->rng_fault_state = True;
717 return NT_STATUS_NOT_IMPLEMENTED;
720 NTSTATUS _eventlog_OpenEventLogA(pipes_struct *p, struct eventlog_OpenEventLogA *r)
722 p->rng_fault_state = True;
723 return NT_STATUS_NOT_IMPLEMENTED;
726 NTSTATUS _eventlog_RegisterEventSourceA(pipes_struct *p, struct eventlog_RegisterEventSourceA *r)
728 p->rng_fault_state = True;
729 return NT_STATUS_NOT_IMPLEMENTED;
732 NTSTATUS _eventlog_OpenBackupEventLogA(pipes_struct *p, struct eventlog_OpenBackupEventLogA *r)
734 p->rng_fault_state = True;
735 return NT_STATUS_NOT_IMPLEMENTED;
738 NTSTATUS _eventlog_ReadEventLogA(pipes_struct *p, struct eventlog_ReadEventLogA *r)
740 p->rng_fault_state = True;
741 return NT_STATUS_NOT_IMPLEMENTED;
744 NTSTATUS _eventlog_ReportEventA(pipes_struct *p, struct eventlog_ReportEventA *r)
746 p->rng_fault_state = True;
747 return NT_STATUS_NOT_IMPLEMENTED;
750 NTSTATUS _eventlog_RegisterClusterSvc(pipes_struct *p, struct eventlog_RegisterClusterSvc *r)
752 p->rng_fault_state = True;
753 return NT_STATUS_NOT_IMPLEMENTED;
756 NTSTATUS _eventlog_DeregisterClusterSvc(pipes_struct *p, struct eventlog_DeregisterClusterSvc *r)
758 p->rng_fault_state = True;
759 return NT_STATUS_NOT_IMPLEMENTED;
762 NTSTATUS _eventlog_WriteClusterEvents(pipes_struct *p, struct eventlog_WriteClusterEvents *r)
764 p->rng_fault_state = True;
765 return NT_STATUS_NOT_IMPLEMENTED;
768 NTSTATUS _eventlog_ReportEventAndSourceW(pipes_struct *p, struct eventlog_ReportEventAndSourceW *r)
770 p->rng_fault_state = True;
771 return NT_STATUS_NOT_IMPLEMENTED;