Print this page
1575 untangle libmlrpc ... (smbsrv)
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/smbsrv/libmlsvc/common/eventlog_svc.c
+++ new/usr/src/lib/smbsrv/libmlsvc/common/eventlog_svc.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 + * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
24 25 */
25 26
26 27 /*
27 28 * Event Log Service RPC (LOGR) interface definition.
28 29 */
29 30 #include <sys/utsname.h>
30 31 #include <unistd.h>
31 32 #include <strings.h>
33 +#include <libmlrpc/libmlrpc.h>
32 34 #include <smbsrv/libsmb.h>
33 -#include <smbsrv/libmlrpc.h>
34 35 #include <smbsrv/nmpipes.h>
35 36 #include <smbsrv/libmlsvc.h>
36 37 #include <smbsrv/ndl/eventlog.ndl>
37 38
38 39
39 40 #define LOGR_FWD +1
40 41 #define LOGR_REW -1
41 42 #define LOGR_RECORD_SIGNATURE 0x654C664C
42 43
43 44 #define LOGR_PRI(p) ((p) & LOG_PRIMASK)
44 45 #define LOGR_WNSTRLEN(S) ((strlen((S)) + 1) * sizeof (smb_wchar_t))
45 46
46 47 #define LOGR_MSG_DWORD_OFFSET 12
47 48 #define LOGR_MSG_WORD_OFFSET 4
48 49
49 50 /*
50 51 * READ flags for EventLogRead
51 52 *
52 53 * EVENTLOG_SEEK_READ
53 54 * The read operation proceeds from the record specified by the
54 55 * dwRecordOffset parameter. This flag cannot be used with
55 56 * EVENTLOG_SEQUENTIAL_READ.
56 57 *
57 58 * EVENTLOG_SEQUENTIAL_READ
58 59 * The read operation proceeds sequentially from the last call to the
59 60 * ReadEventLog function using this handle. This flag cannot be used
60 61 * with EVENTLOG_SEEK_READ.
61 62 *
62 63 * If the buffer is large enough, more than one record can be read at
63 64 * the specified seek position; you must specify one of the following
64 65 * flags to indicate the direction for successive read operations.
65 66 *
66 67 * EVENTLOG_FORWARDS_READ
67 68 * The log is read in chronological order. This flag cannot be used
68 69 * with EVENTLOG_BACKWARDS_READ.
69 70 *
70 71 * EVENTLOG_BACKWARDS_READ
71 72 * The log is read in reverse chronological order. This flag cannot be
72 73 * used with EVENTLOG_FORWARDS_READ.
73 74 */
74 75 #define EVENTLOG_SEQUENTIAL_READ 0x0001
75 76 #define EVENTLOG_SEEK_READ 0x0002
76 77 #define EVENTLOG_FORWARDS_READ 0x0004
77 78 #define EVENTLOG_BACKWARDS_READ 0x0008
78 79
79 80 /*
80 81 * The types of events that can be logged.
81 82 */
82 83 #define EVENTLOG_SUCCESS 0x0000
83 84 #define EVENTLOG_ERROR_TYPE 0x0001
84 85 #define EVENTLOG_WARNING_TYPE 0x0002
85 86 #define EVENTLOG_INFORMATION_TYPE 0x0004
86 87 #define EVENTLOG_AUDIT_SUCCESS 0x0008
87 88 #define EVENTLOG_AUDIT_FAILURE 0x0010
88 89
89 90 /*
90 91 * Event Identifiers
91 92 *
92 93 * Event identifiers uniquely identify a particular event. Each event
93 94 * source can define its own numbered events and the description strings
94 95 * to which they are mapped. Event viewers can present these strings to
95 96 * the user. They should help the user understand what went wrong and
96 97 * suggest what actions to take. Direct the description at users solving
97 98 * their own problems, not at administrators or support technicians.
98 99 * Make the description clear and concise and avoid culture-specific
99 100 * phrases.
100 101 *
101 102 * The following diagram illustrates the format of an event identifier.
102 103 *
103 104 * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
104 105 * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
105 106 * +---+-+-+-----------------------+-------------------------------+
106 107 * |Sev|C|R| Facility | Code |
107 108 * +---+-+-+-----------------------+-------------------------------+
108 109 *
109 110 * Sev
110 111 * Indicates the severity. This is one of the following values:
111 112 * 00 - Success
112 113 * 01 - Informational
113 114 * 10 - Warning
114 115 * 11 - Error
115 116 *
116 117 * C
117 118 * Indicates a customer code (1) or a system code (0).
118 119 * R
119 120 * Reserved bit.
120 121 * Facility
121 122 * Facility code.
122 123 * Code
123 124 * Status code for the facility.
124 125 */
125 126 #define EVENTID_SEVERITY_SUCCESS 0x00000000
126 127 #define EVENTID_SEVERITY_INFO 0x40000000
127 128 #define EVENTID_SEVERITY_WARNING 0x80000000
128 129 #define EVENTID_SEVERITY_ERROR 0xC0000000
129 130
130 131 #define EVENTID_SYSTEM_CODE 0x00000000
131 132 #define EVENTID_CUSTOMER_CODE 0x20000000
132 133
133 134 static int logr_s_EventLogClose(void *, ndr_xa_t *);
134 135 static int logr_s_EventLogQueryCount(void *, ndr_xa_t *);
135 136 static int logr_s_EventLogGetOldestRec(void *, ndr_xa_t *);
136 137 static int logr_s_EventLogOpen(void *, ndr_xa_t *);
137 138 static int logr_s_EventLogRead(void *, ndr_xa_t *);
138 139
139 140 static ndr_stub_table_t logr_stub_table[] = {
140 141 { logr_s_EventLogClose, LOGR_OPNUM_EventLogClose },
141 142 { logr_s_EventLogQueryCount, LOGR_OPNUM_EventLogQueryCount },
142 143 { logr_s_EventLogGetOldestRec, LOGR_OPNUM_EventLogGetOldestRec },
143 144 { logr_s_EventLogOpen, LOGR_OPNUM_EventLogOpen },
144 145 { logr_s_EventLogRead, LOGR_OPNUM_EventLogRead },
145 146 {0}
146 147 };
147 148
148 149 static ndr_service_t logr_service = {
149 150 "LOGR", /* name */
150 151 "Event Log Service", /* desc */
151 152 "\\eventlog", /* endpoint */
152 153 PIPE_NTSVCS, /* sec_addr_port */
153 154 "82273fdc-e32a-18c3-3f78-827929dc23ea", 0, /* abstract */
154 155 NDR_TRANSFER_SYNTAX_UUID, 2, /* transfer */
155 156 0, /* no bind_instance_size */
156 157 0, /* no bind_req() */
157 158 0, /* no unbind_and_close() */
158 159 0, /* use generic_call_stub() */
159 160 &TYPEINFO(logr_interface), /* interface ti */
160 161 logr_stub_table /* stub_table */
161 162 };
162 163
163 164 /*
164 165 * logr_initialize
165 166 *
166 167 * This function registers the LOGR RPC interface with the RPC runtime
167 168 * library. It must be called in order to use either the client side
168 169 * or the server side functions.
169 170 */
170 171 void
171 172 logr_initialize(void)
172 173 {
173 174 (void) ndr_svc_register(&logr_service);
174 175 logr_init();
175 176 }
176 177
177 178 void
178 179 logr_finalize(void)
179 180 {
180 181 logr_fini();
181 182 }
182 183
183 184 /*
184 185 * logr_hdlookup
185 186 *
186 187 * Handle lookup wrapper to validate the local service and/or manager context.
187 188 */
188 189 static ndr_handle_t *
189 190 logr_hdlookup(ndr_xa_t *mxa, ndr_hdid_t *id)
190 191 {
191 192 ndr_handle_t *hd;
192 193 logr_context_t *ctx;
193 194
194 195 if ((hd = ndr_hdlookup(mxa, id)) == NULL)
195 196 return (NULL);
196 197
197 198 if ((ctx = (logr_context_t *)hd->nh_data) == NULL)
198 199 return (NULL);
199 200
200 201 if (ctx->lc_source_name == NULL)
201 202 return (NULL);
202 203
203 204 return (hd);
204 205 }
205 206
206 207 /*
207 208 * logr_context_data_free
208 209 *
209 210 * Callback to free the context data associated with local service
210 211 * and/or manager context.
211 212 */
212 213 static void
213 214 logr_context_data_free(void *ctxp)
214 215 {
215 216 logr_context_t *ctx = (logr_context_t *)ctxp;
216 217
217 218 if (ctx == NULL)
218 219 return;
219 220
220 221 free(ctx->lc_source_name);
221 222 free(ctx->lc_cached_read_data->rd_log);
222 223 free(ctx->lc_cached_read_data);
223 224 free(ctx);
224 225 ctx = NULL;
225 226 }
226 227
227 228 /*
228 229 * logr_hdalloc
229 230 *
230 231 * Handle allocation wrapper to setup the local manager context.
231 232 */
232 233 static ndr_hdid_t *
233 234 logr_hdalloc(ndr_xa_t *mxa, char *logname)
234 235 {
235 236 logr_context_t *ctx;
236 237
237 238 if ((ctx = malloc(sizeof (logr_context_t))) == NULL)
238 239 return (NULL);
239 240 bzero(ctx, sizeof (logr_context_t));
240 241
241 242 ctx->lc_source_name = strdup(logname);
242 243 if (ctx->lc_source_name == NULL) {
243 244 free(ctx);
244 245 return (NULL);
245 246 }
246 247
247 248 if (logr_get_snapshot(ctx) != 0) {
248 249 free(ctx->lc_source_name);
249 250 free(ctx);
250 251 return (NULL);
251 252 }
252 253
253 254 return (ndr_hdalloc(mxa, ctx));
254 255 }
255 256
256 257 /*
257 258 * logr_s_EventLogClose
258 259 *
259 260 * This is a request to close the LOGR interface specified by handle.
260 261 * Free the handle and associated resources, and zero out the result
261 262 * handle for the client.
262 263 */
263 264 static int
264 265 logr_s_EventLogClose(void *arg, ndr_xa_t *mxa)
265 266 {
266 267 struct logr_EventLogClose *param = arg;
267 268 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle;
268 269 ndr_handle_t *hd;
269 270
270 271 if ((hd = ndr_hdlookup(mxa, id)) == NULL) {
271 272 bzero(¶m->result_handle, sizeof (logr_handle_t));
272 273 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
273 274 return (NDR_DRC_OK);
274 275 }
275 276 logr_context_data_free(hd->nh_data);
276 277 ndr_hdfree(mxa, id);
277 278
278 279 bzero(¶m->result_handle, sizeof (logr_handle_t));
279 280 param->status = NT_STATUS_SUCCESS;
280 281
281 282 return (NDR_DRC_OK);
282 283 }
283 284
284 285 /*
285 286 * logr_s_EventLogOpen
286 287 *
287 288 * Open the event log. Not supported yet.
288 289 */
289 290 /*ARGSUSED*/
290 291 static int
291 292 logr_s_EventLogOpen(void *arg, ndr_xa_t *mxa)
292 293 {
293 294 struct logr_EventLogOpen *param = arg;
294 295 ndr_hdid_t *id = NULL;
295 296 ndr_handle_t *hd;
296 297 char *log_name = NULL;
297 298
298 299 if (!ndr_is_admin(mxa)) {
299 300 bzero(¶m->handle, sizeof (logr_handle_t));
300 301 param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
301 302 return (NDR_DRC_OK);
302 303 }
303 304
304 305 if (param->log_name.length != 0)
305 306 log_name = (char *)param->log_name.str;
306 307
307 308 if (!logr_is_supported(log_name)) {
308 309 bzero(¶m->handle, sizeof (logr_handle_t));
309 310 param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
310 311 return (NDR_DRC_OK);
311 312 }
312 313
313 314 id = logr_hdalloc(mxa, log_name);
314 315 if (id && ((hd = logr_hdlookup(mxa, id)) != NULL)) {
315 316 hd->nh_data_free = logr_context_data_free;
316 317 bcopy(id, ¶m->handle, sizeof (logr_handle_t));
317 318 param->status = NT_STATUS_SUCCESS;
318 319 } else {
319 320 bzero(¶m->handle, sizeof (logr_handle_t));
320 321 param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
321 322 }
322 323
323 324 return (NDR_DRC_OK);
324 325 }
325 326
326 327 /*
327 328 * logr_s_EventLogQueryCount
328 329 *
329 330 * take a snapshot from system log, assign it to the given handle.
330 331 * return number of log entries in the snapshot as result of RPC
331 332 * call.
332 333 */
333 334 static int
334 335 logr_s_EventLogQueryCount(void *arg, ndr_xa_t *mxa)
335 336 {
336 337 struct logr_EventLogQueryCount *param = arg;
337 338 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle;
338 339 ndr_handle_t *hd;
339 340 logr_context_t *ctx;
340 341 logr_read_data_t *data;
341 342
342 343 if ((hd = logr_hdlookup(mxa, id)) == NULL) {
343 344 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
344 345 return (NDR_DRC_OK);
345 346 }
346 347
347 348 ctx = (logr_context_t *)hd->nh_data;
348 349 data = ctx->lc_cached_read_data;
349 350
350 351 param->rec_num = data->rd_tot_recnum;
351 352 param->status = NT_STATUS_SUCCESS;
352 353 return (NDR_DRC_OK);
353 354 }
354 355
355 356 /*
356 357 * logr_s_EventLogGetOldestRec
357 358 *
358 359 * Return oldest record number in the snapshot as result of RPC call.
359 360 */
360 361 static int
361 362 logr_s_EventLogGetOldestRec(void *arg, ndr_xa_t *mxa)
362 363 {
363 364 struct logr_EventLogGetOldestRec *param = arg;
364 365 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle;
365 366 ndr_handle_t *hd;
366 367 logr_context_t *ctx;
367 368 logr_read_data_t *data;
368 369
369 370 if ((hd = logr_hdlookup(mxa, id)) == NULL) {
370 371 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
371 372 return (NDR_DRC_OK);
372 373 }
373 374
374 375 ctx = (logr_context_t *)hd->nh_data;
375 376 data = ctx->lc_cached_read_data;
376 377
377 378 param->oldest_rec = data->rd_log->li_idx - data->rd_tot_recnum + 1;
378 379
379 380 param->status = NT_STATUS_SUCCESS;
380 381 return (NDR_DRC_OK);
381 382 }
382 383
383 384 /*
384 385 * logr_set_event_typeid
385 386 *
386 387 * Map the local system log priority to the event type and event ID
387 388 * for Windows events.
388 389 */
389 390 void
390 391 logr_set_event_typeid(int le_pri, WORD *etype, DWORD *eid)
391 392 {
392 393 switch (LOGR_PRI(le_pri)) {
393 394 case LOG_EMERG:
394 395 case LOG_ALERT:
395 396 case LOG_CRIT:
396 397 case LOG_ERR:
397 398 *eid = EVENTID_SEVERITY_ERROR;
398 399 *etype = EVENTLOG_ERROR_TYPE;
399 400 break;
400 401 case LOG_WARNING:
401 402 *eid = EVENTID_SEVERITY_WARNING;
402 403 *etype = EVENTLOG_WARNING_TYPE;
403 404 break;
404 405 case LOG_NOTICE:
405 406 case LOG_INFO:
406 407 case LOG_DEBUG:
407 408 *eid = EVENTID_SEVERITY_INFO;
408 409 *etype = EVENTLOG_INFORMATION_TYPE;
409 410 break;
410 411 default:
411 412 *eid = EVENTID_SEVERITY_SUCCESS;
412 413 *etype = EVENTLOG_SUCCESS;
413 414 }
414 415 }
415 416
416 417 /*
417 418 * logr_get_entry
418 419 *
419 420 * Gets a log entry.
420 421 */
421 422 static logr_entry_t *
422 423 logr_get_entry(logr_info_t *linfo, int entno)
423 424 {
424 425 return (&linfo->li_entry[entno]);
425 426 }
426 427
427 428 /*
428 429 * logr_set_logrecord
429 430 *
430 431 * Fill a Windows event record based on a local system log record.
431 432 */
432 433 static void
433 434 logr_set_logrecord(char *src_name, logr_entry_t *le,
434 435 DWORD recno, logr_record_t *rec)
435 436 {
436 437 int srcname_len = 0, hostname_len = 0, len;
437 438 int str_offs, sh_len;
438 439 smb_wchar_t wcs_hostname[MAXHOSTNAMELEN];
439 440 smb_wchar_t wcs_srcname[SYS_NMLN * 2];
440 441
441 442 (void) smb_mbstowcs(wcs_srcname, src_name,
442 443 strlen(src_name) + 1);
443 444 srcname_len = LOGR_WNSTRLEN(src_name);
444 445
445 446 /* Because, Solaris allows remote logging, need to get hostname here */
446 447 (void) smb_mbstowcs(wcs_hostname, le->le_hostname,
447 448 strlen(le->le_hostname) + 1);
448 449 hostname_len = LOGR_WNSTRLEN(le->le_hostname);
449 450
450 451 sh_len = srcname_len + hostname_len;
451 452 str_offs = LOGR_MSG_DWORD_OFFSET * sizeof (DWORD) +
452 453 LOGR_MSG_WORD_OFFSET * sizeof (WORD) + sh_len;
453 454
454 455 rec->Length1 = sizeof (logr_record_t);
455 456 rec->Reserved = LOGR_RECORD_SIGNATURE;
456 457 rec->RecordNumber = recno;
457 458 rec->TimeGenerated = le->le_timestamp.tv_sec;
458 459 rec->TimeWritten = le->le_timestamp.tv_sec;
459 460 logr_set_event_typeid(le->le_pri, &rec->EventType, &rec->EventID);
460 461 rec->NumStrings = 1;
461 462 rec->EventCategory = 0;
462 463 rec->ReservedFlags = 0;
463 464 rec->ClosingRecordNumber = 0;
464 465 rec->StringOffset = str_offs;
465 466 rec->UserSidLength = 0;
466 467 rec->UserSidOffset = 0;
467 468 rec->DataLength = 0;
468 469 rec->DataOffset = 0;
469 470
470 471 bzero(rec->info, LOGR_MAXENTRYLEN);
471 472 (void) memcpy(rec->info, wcs_srcname, srcname_len);
472 473 (void) memcpy(rec->info + srcname_len, wcs_hostname, hostname_len);
473 474
474 475 len = strlen(le->le_msg) + 1;
475 476 if (len > 0)
476 477 /*LINTED E_BAD_PTR_CAST_ALIGN*/
477 478 (void) smb_mbstowcs((smb_wchar_t *)(rec->info + sh_len),
478 479 le->le_msg, len);
479 480
480 481 rec->Length2 = sizeof (logr_record_t);
481 482 }
482 483
483 484 /*
484 485 * logr_s_EventLogRead
485 486 *
486 487 * Reads a whole number of entries from system log. The function can
487 488 * read log entries in chronological or reverse chronological order.
488 489 */
489 490 static int
490 491 logr_s_EventLogRead(void *arg, ndr_xa_t *mxa)
491 492 {
492 493 struct logr_EventLogRead *param = arg;
493 494 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle;
494 495 ndr_handle_t *hd;
495 496 logr_read_data_t *rdata;
496 497 logr_entry_t *le;
497 498 DWORD ent_no, ent_num, ent_remain;
498 499 logr_record_t *rec;
499 500 BYTE *buf;
500 501 int dir, ent_per_req, iter;
501 502 logr_context_t *ctx;
502 503
503 504 if ((hd = logr_hdlookup(mxa, id)) == NULL) {
504 505 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
505 506 return (NDR_DRC_OK);
506 507 }
507 508
508 509 ctx = (logr_context_t *)hd->nh_data;
509 510 rdata = ctx->lc_cached_read_data;
510 511 if (rdata == NULL) {
511 512 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
512 513 return (NDR_DRC_OK);
513 514 }
514 515
515 516 dir = (param->read_flags & EVENTLOG_FORWARDS_READ) ?
516 517 LOGR_FWD : LOGR_REW;
517 518
518 519 if (param->read_flags & EVENTLOG_SEEK_READ)
519 520 rdata->rd_last_sentrec = param->rec_offset;
520 521 else if (rdata->rd_first_read)
521 522 /*
522 523 * set last record number which is read for
523 524 * the first iteration of sequential read.
524 525 */
525 526 rdata->rd_last_sentrec = (dir == LOGR_FWD)
526 527 ? (rdata->rd_log->li_idx - rdata->rd_tot_recnum)
527 528 : rdata->rd_log->li_idx;
528 529
529 530 ent_remain = (dir == LOGR_FWD)
530 531 ? (rdata->rd_tot_recnum - rdata->rd_last_sentrec)
531 532 : rdata->rd_last_sentrec;
532 533
533 534 /*
534 535 * function should return as many whole log entries as
535 536 * will fit in the buffer; it should not return partial
536 537 * entries, even if there is room in the buffer.
537 538 */
538 539 ent_per_req = param->nbytes_to_read / sizeof (logr_record_t);
539 540 if (ent_remain > ent_per_req)
540 541 ent_remain = ent_per_req;
541 542
542 543 if (ent_remain == 0) {
543 544 /*
544 545 * Send this error to Windows client so that it
545 546 * can figure out that there is no more record
546 547 * to read.
547 548 */
548 549 param->buf = NDR_STRDUP(mxa, "");
549 550 param->sent_size = 0;
550 551 param->status = NT_SC_ERROR(NT_STATUS_END_OF_FILE);
551 552 return (NDR_DRC_OK);
552 553 }
553 554
554 555 param->buf = NDR_MALLOC(mxa, param->nbytes_to_read);
555 556 buf = (BYTE *)param->buf;
556 557
557 558 for (ent_num = 0, ent_no = rdata->rd_last_sentrec;
558 559 ent_num < ent_remain; ent_num++, ent_no += dir) {
559 560
560 561 iter = ent_no & LOGR_NMSGMASK;
561 562 if (dir == LOGR_REW)
562 563 iter = (ent_no - 1) & LOGR_NMSGMASK;
563 564
564 565 le = logr_get_entry(rdata->rd_log, iter);
565 566
566 567 /*LINTED E_BAD_PTR_CAST_ALIGN*/
567 568 rec = (logr_record_t *)buf;
568 569 logr_set_logrecord(ctx->lc_source_name, le, ent_no, rec);
569 570 buf += sizeof (logr_record_t);
570 571 }
571 572
572 573 rdata->rd_last_sentrec = ent_no;
573 574 rdata->rd_first_read = 0;
574 575
575 576 param->sent_size = sizeof (logr_record_t) * ent_remain;
576 577 param->status = NT_STATUS_SUCCESS;
577 578
578 579 return (NDR_DRC_OK);
579 580 }
↓ open down ↓ |
536 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX