windows-afsifs-20050804
[openafs.git] / src / WINNT / afsrdr / ifs_rpc.c
1 /* copyright (c) 2005
2  * the regents of the university of michigan
3  * all rights reserved
4  * 
5  * permission is granted to use, copy, create derivative works and
6  * redistribute this software and such derivative works for any purpose,
7  * so long as the name of the university of michigan is not used in
8  * any advertising or publicity pertaining to the use or distribution
9  * of this software without specific, written prior authorization.  if
10  * the above copyright notice or any other identification of the
11  * university of michigan is included in any copy of any portion of
12  * this software, then the disclaimer below must also be included.
13  * 
14  * this software is provided as is, without representation from the
15  * university of michigan as to its fitness for any purpose, and without
16  * warranty by the university of michigan of any kind, either express 
17  * or implied, including without limitation the implied warranties of
18  * merchantability and fitness for a particular purpose.  the regents
19  * of the university of michigan shall not be liable for any damages,   
20  * including special, indirect, incidental, or consequential damages, 
21  * with respect to any claim arising out or in connection with the use
22  * of the software, even if it has been or is hereafter advised of the
23  * possibility of such damages.
24  */
25
26 /* versioning history
27  * 
28  * 03-jun 2005 (eric williams) entered into versioning
29  */
30
31 #ifdef RPC_KERN
32 #include <ntifs.h>
33 #include "ifs_rpc.h"
34 #include "afsrdr.h"
35 #else
36 #include "ifs_rpc.h"
37 #endif
38 #include "kif.h"
39
40 /* general internal functions */
41 rpc_t *rpc_create(int size_hint);
42 void rpc_destroy(rpc_t *rpc);
43 int rpc_marshal_long(rpc_t *rpc, ULONG data);
44 int rpc_marshal_longlong(rpc_t *rpc, LARGE_INTEGER data);
45 int rpc_marshal_wstr(rpc_t *rpc, WCHAR *str);
46 int rpc_unmarshal_long(rpc_t *rpc, ULONG *data);
47 int rpc_unmarshal_longlong(rpc_t *rpc, LARGE_INTEGER *data);
48 int rpc_unmarshal_wstr(rpc_t *rpc, WCHAR *str);
49
50 /* kernel-queue specific internal functions */
51 #ifdef RPC_KERN
52 int rpc_queue(rpc_t *rpc);
53 rpc_queue_bulk(rpc_t *rpc, char *out_bulk, ULONG out_len, char *in_bulk, ULONG in_len);
54 rpc_cancel(rpc_t *rpc);
55 rpc_send_reg(rpc_t *rpc, char *out_buf);
56 rpc_queue_bulk_mdl(rpc_t *rpc, MDL *mdl);
57 rpc_t *rpc_find(int id);
58 rpc_t *rpc_upgrade(rpc_t *rpc, int old_status, int new_status);
59 rpc_wait(rpc_t *rpc, BOOLEAN long_op);
60 rpc_send_mdl(rpc_t *rpc, char *out_buf);
61 #endif
62
63
64 /****** rpc security kernel functions ******/
65 /* before making an upcall from kernel code, set the security context by
66  * passing the access_token to rpc_set_context.  remove the context after all
67  * upcalls are done.  the rpc library automatically checks and sets this
68  * same context on the other end. */
69 #ifdef RPC_KERN
70 struct rpc_cred_map_entry
71 {
72     void *token;
73     PETHREAD thread;
74     int refs;
75 };
76
77 struct rpc_cred_map_entry cred_map[MAX_CRED_MAPS];
78 rpc_t *rpc_list_head = NULL;
79 long num_rpcs = 0;
80
81 rpc_set_context(void *context)
82 {
83     int x, empty, ret;
84     PETHREAD thd;
85
86     thd = PsGetCurrentThread();
87     empty = -1;
88     ret = 0;
89
90     ifs_lock_rpcs();
91     for (x = 0; x < MAX_CRED_MAPS; x++)
92     {
93         if (cred_map[x].thread == NULL)
94             empty = x;
95         if (cred_map[x].thread == thd)
96         {
97             //////FIX///ASSERT(cred_map[x].token == context);
98             cred_map[x].refs++;
99             //cred_map[x].token = context;
100             goto done;
101         }
102     }
103     if (empty != -1)
104     {
105         cred_map[empty].thread = thd;
106         cred_map[empty].token = context;
107         cred_map[empty].refs = 1;
108     }
109     else
110         ret = -1;
111
112   done:
113     ifs_unlock_rpcs();
114     return ret;
115 }
116
117 void *rpc_get_context()
118 {
119     int x;
120     PETHREAD thd;
121
122     thd = PsGetCurrentThread();
123
124     // no lock
125     for (x = 0; x < MAX_CRED_MAPS; x++)
126         if (cred_map[x].thread == thd)
127             return cred_map[x].token;
128     // no unlock
129     return NULL;
130 }
131
132 rpc_remove_context()
133 {
134     int x;
135     PETHREAD thd;
136
137     thd = PsGetCurrentThread();
138     ifs_lock_rpcs();
139     for (x = 0; x < MAX_CRED_MAPS; x++)
140         if (cred_map[x].thread == thd)
141         {
142             if (cred_map[x].refs > 1)
143                 {
144                 cred_map[x].refs--;
145                 }
146             else
147                 {
148                 cred_map[x].token = NULL;
149                 cred_map[x].thread = NULL;
150                 }
151             ifs_unlock_rpcs();
152             return 0;
153         }
154
155     ifs_unlock_rpcs();
156     return -1;
157 }
158 #endif
159
160
161 /* rpc stubs in kernel */
162 #ifdef RPC_KERN
163 rpc_t *rpc_create(int size_hint)
164 {
165     ULONG size;
166     rpc_t *rpc;
167     SECURITY_SUBJECT_CONTEXT subj_context;
168     PACCESS_TOKEN acc_token;
169     LUID auth_id;
170     LARGE_INTEGER user_id;
171     NTSTATUS status;
172     HANDLE token;
173
174     /* get user's identification from auth token*/
175     token = rpc_get_context();
176     ASSERT(token);
177     status = SeQueryAuthenticationIdToken(token, &auth_id);
178
179     user_id.LowPart = auth_id.LowPart;
180     user_id.HighPart = auth_id.HighPart;
181
182     ifs_lock_rpcs();
183
184     if (!(rpc = rpc_upgrade(NULL, 0, 1)))
185     {
186         size = sizeof(rpc_t) + 2*RPC_BUF_SIZE;
187         rpc = ExAllocatePoolWithTag(NonPagedPool, size, 0x1234);
188         if (!rpc)
189             return NULL;
190         num_rpcs++;
191         memset(rpc, 0, size);
192         rpc->next = rpc_list_head;
193         rpc_list_head = rpc;
194         rpc_upgrade(rpc, 0, 1);
195     }
196
197     rpc->out_buf = rpc->out_pos = (char*)(rpc+1);
198     rpc->in_buf = rpc->in_pos = ((char*)(rpc+1))+RPC_BUF_SIZE;
199
200     rpc->key = rand() + 10;
201     rpc_marshal_long(rpc, rpc->key);
202     rpc->bulk_out_len = (ULONG*)rpc->out_pos;
203     rpc_marshal_long(rpc, 0);
204
205 #if 0
206     /* another way of obtaining credentials, with different effects */
207     SeCaptureSubjectContext(&subj_context);
208     acc_token = SeQuerySubjectContextToken(&subj_context);
209     status = SeQueryAuthenticationIdToken(acc_token, &auth_id);
210
211     user_id.LowPart = auth_id.LowPart;
212     user_id.HighPart = auth_id.HighPart;
213     SeReleaseSubjectContext(&subj_context);
214 #endif
215
216     rpc_marshal_longlong(rpc, user_id);
217
218     ifs_unlock_rpcs();
219
220     return rpc;
221 }
222
223 void rpc_destroy(rpc_t *rpc)
224 {
225     rpc_t *curr;
226     int count;
227
228     ifs_lock_rpcs();
229
230     if (rpc_upgrade(rpc, -1, 0))
231         ;
232
233     ifs_unlock_rpcs();
234 }
235 #endif
236
237
238 /* rpc internal functions for usermode */
239 #ifndef RPC_KERN
240 rpc_t *rpc_create(int size_hint)
241 {
242     ULONG size;
243     rpc_t *rpc;
244     ULONG status;
245
246     size = sizeof(rpc_t) + 2*RPC_BUF_SIZE;
247     rpc = malloc(size);
248     if (!rpc)
249         osi_panic("ifs_rpc: alloc buffer", __FILE__, __LINE__);
250     memset(rpc, 0, size);
251
252     rpc->out_buf = rpc->out_pos = (char*)(rpc+1);
253     rpc->in_buf = rpc->in_pos = ((char*)(rpc+1)) + RPC_BUF_SIZE;
254
255     rpc->key = rand() + 10;
256     rpc_marshal_long(rpc, rpc->key);
257
258     return rpc;
259 }
260
261 void rpc_destroy(rpc_t *rpc)
262 {
263     if (!rpc)
264         return;
265
266     free(rpc);
267 }
268
269 rpc_transact(rpc_t *rpc)
270 {
271     HANDLE hf;
272     int ret;
273     ULONG header_len;
274     DWORD err, read = 0;
275
276     if (!rpc)
277         return IFSL_GENERIC_FAILURE;
278
279     header_len = rpc->out_pos - rpc->out_buf;
280
281     read = RPC_BUF_SIZE;
282     return ifs_TransactRpc(rpc->out_buf, header_len, rpc->in_buf, &read);
283 }
284 #endif
285
286
287 /* upcall stubs */
288 #ifdef RPC_KERN
289 uc_namei(WCHAR *name, ULONG *fid)
290 {
291     rpc_t *rpc;
292     ULONG status;
293     MDL *mdl;
294
295         /* consider putting namei cache here */
296
297     rpc = rpc_create(0);
298         if (!rpc)
299                 return IFSL_MEMORY;
300
301     rpc_marshal_long(rpc, RPC_NAMEI);
302     rpc_marshal_long(rpc, wcslen(name));
303
304     rpc_queue_bulk(rpc, (void*)name, (wcslen(name)+1)*sizeof(wchar_t), NULL, 0);
305
306     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
307     {
308         rpc_cancel(rpc);
309         rpt0(("cancel", "cancel namei"));
310         return IFSL_RPC_TIMEOUT;
311     }
312
313     rpc_unmarshal_long(rpc, &status);
314     rpc_unmarshal_long(rpc, fid);
315
316     rpc_destroy(rpc);
317     return status;
318 }
319
320 uc_check_access(ULONG fid, ULONG access, ULONG *granted)
321 {
322     rpc_t *rpc;
323     ULONG status;
324
325     rpc = rpc_create(0);
326         if (!rpc)
327                 return IFSL_MEMORY;
328
329     rpc_marshal_long(rpc, RPC_CHECK_ACCESS);
330     rpc_marshal_long(rpc, fid);
331     rpc_marshal_long(rpc, access);
332
333     rpc_queue(rpc);
334     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
335     {
336         rpc_cancel(rpc);
337         rpt0(("cancel", "cancel access"));
338         return IFSL_RPC_TIMEOUT;
339     }
340
341     rpc_unmarshal_long(rpc, &status);
342     rpc_unmarshal_long(rpc, granted);
343
344     rpc_destroy(rpc);
345     return status;
346 }
347
348 uc_create(WCHAR *name, ULONG attribs, LARGE_INTEGER alloc, ULONG access, ULONG *granted, ULONG *fid)
349 {
350     rpc_t *rpc;
351     ULONG status;
352
353     rpc = rpc_create(0);
354         if (!rpc)
355                 return IFSL_MEMORY;
356
357     rpc_marshal_long(rpc, RPC_CREATE);
358     rpc_marshal_long(rpc, attribs);
359     rpc_marshal_longlong(rpc, alloc);
360     rpc_marshal_long(rpc, access);
361
362     rpc_queue_bulk(rpc, (void*)name, (wcslen(name)+1)*sizeof(wchar_t), NULL, 0);
363     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
364     {
365         rpc_cancel(rpc);
366         rpt0(("cancel", "cancel create"));
367         return IFSL_RPC_TIMEOUT;
368     }
369
370     rpc_unmarshal_long(rpc, &status);
371     rpc_unmarshal_long(rpc, granted);
372     rpc_unmarshal_long(rpc, fid);
373
374     rpc_destroy(rpc);
375     return status;
376 }
377
378 uc_stat(ULONG fid, ULONG *attribs, LARGE_INTEGER *size, LARGE_INTEGER *creation, LARGE_INTEGER *access, LARGE_INTEGER *change, LARGE_INTEGER *written)
379 {
380     rpc_t *rpc;
381     ULONG status;
382
383     rpc = rpc_create(0);
384         if (!rpc)
385                 return IFSL_MEMORY;
386
387     rpc_marshal_long(rpc, RPC_STAT);
388     rpc_marshal_long(rpc, fid);
389
390     rpc_queue(rpc);
391     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
392     {
393         rpc_cancel(rpc);
394         rpt0(("cancel", "cancel stat"));
395         return IFSL_RPC_TIMEOUT;
396     }
397
398     rpc_unmarshal_long(rpc, &status);
399     rpc_unmarshal_long(rpc, attribs);
400     rpc_unmarshal_longlong(rpc, size);
401     rpc_unmarshal_longlong(rpc, creation);
402     rpc_unmarshal_longlong(rpc, access);
403     rpc_unmarshal_longlong(rpc, change);
404     rpc_unmarshal_longlong(rpc, written);
405
406     rpc_destroy(rpc);
407     return status;
408 }
409
410 uc_setinfo(ULONG fid, ULONG attribs, LARGE_INTEGER creation, LARGE_INTEGER access, LARGE_INTEGER change, LARGE_INTEGER written)
411 {
412     rpc_t *rpc;
413     ULONG status;
414
415     rpc = rpc_create(0);
416         if (!rpc)
417                 return IFSL_MEMORY;
418
419     rpc_marshal_long(rpc, RPC_SETINFO);
420     rpc_marshal_long(rpc, fid);
421     rpc_marshal_long(rpc, attribs);
422     rpc_marshal_longlong(rpc, creation);
423     rpc_marshal_longlong(rpc, access);
424     rpc_marshal_longlong(rpc, change);
425     rpc_marshal_longlong(rpc, written);
426
427
428     rpc_queue(rpc);
429     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
430     {
431         rpc_cancel(rpc);
432         rpt0(("cancel", "cancel setinfo"));
433         return IFSL_RPC_TIMEOUT;
434     }
435
436     rpc_unmarshal_long(rpc, &status);
437
438     rpc_destroy(rpc);
439     return status;
440 }
441
442 uc_trunc(ULONG fid, LARGE_INTEGER size)
443 {
444     rpc_t *rpc;
445     ULONG status;
446
447     rpc = rpc_create(0);
448         if (!rpc)
449                 return IFSL_MEMORY;
450
451     rpc_marshal_long(rpc, RPC_TRUNC);
452     rpc_marshal_long(rpc, fid);
453     rpc_marshal_longlong(rpc, size);
454
455     rpc_queue(rpc);
456     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
457     {
458         rpc_cancel(rpc);
459         rpt0(("cancel", "cancel trunc"));
460         return IFSL_RPC_TIMEOUT;
461     }
462
463     rpc_unmarshal_long(rpc, &status);
464
465     rpc_destroy(rpc);
466     return status;
467 }
468
469 uc_read(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *read, char *data)
470 {
471     rpc_t *rpc;
472     ULONG status;
473
474     rpc = rpc_create(0);
475         if (!rpc)
476                 return IFSL_MEMORY;
477
478     rpc_marshal_long(rpc, RPC_READ);
479     rpc_marshal_long(rpc, fid);
480     rpc_marshal_longlong(rpc, offset);
481     rpc_marshal_long(rpc, length);
482
483     rpc_queue_bulk(rpc, NULL, 0, data, length);
484     if (!rpc_wait(rpc, RPC_TIMEOUT_LONG))
485     {
486         rpc_cancel(rpc);
487         rpt0(("cancel", "cancel read"));
488         return IFSL_RPC_TIMEOUT;
489     }
490
491     rpc_unmarshal_long(rpc, &status);
492     rpc_unmarshal_long(rpc, read);
493
494     rpc_destroy(rpc);
495     return status;
496 }
497
498 uc_write(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *written, char *data)
499 {
500     rpc_t *rpc;
501     ULONG status;
502
503     rpc = rpc_create(0);
504         if (!rpc)
505                 return IFSL_MEMORY;
506
507     rpc_marshal_long(rpc, RPC_WRITE);
508     rpc_marshal_long(rpc, fid);
509     rpc_marshal_longlong(rpc, offset);
510     rpc_marshal_long(rpc, length);
511
512     rpc_queue_bulk(rpc, data, length, NULL, 0);
513     if (!rpc_wait(rpc, RPC_TIMEOUT_LONG))
514     {
515         rpc_cancel(rpc);
516         rpt0(("cancel", "cancel write"));
517         return IFSL_RPC_TIMEOUT;
518     }
519
520     rpc_unmarshal_long(rpc, &status);
521     rpc_unmarshal_long(rpc, written);
522
523     rpc_destroy(rpc);
524     return status;
525 }
526
527 uc_readdir(ULONG fid, LARGE_INTEGER cookie_in, WCHAR *filter, ULONG *count, char *data, ULONG *len)
528 {
529     rpc_t *rpc;
530     ULONG status;
531
532     rpc = rpc_create(0);
533         if (!rpc)
534                 return IFSL_MEMORY;
535
536     rpc_marshal_long(rpc, RPC_READDIR);
537     rpc_marshal_long(rpc, fid);
538     rpc_marshal_longlong(rpc, cookie_in);
539     rpc_marshal_wstr(rpc, filter);
540     rpc_marshal_long(rpc, *len);
541
542     rpc_queue_bulk(rpc, NULL, 0, data, *len);
543     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
544     {
545         rpc_cancel(rpc);
546         rpt0(("cancel", "cancel readdir"));
547         return IFSL_RPC_TIMEOUT;
548     }
549
550     rpc_unmarshal_long(rpc, &status);
551     rpc_unmarshal_long(rpc, count);
552     rpc_unmarshal_long(rpc, len);
553
554     rpc_destroy(rpc);
555     return status;
556 }
557
558 uc_close(ULONG fid)
559 {
560     rpc_t *rpc;
561     ULONG status;
562
563     rpc = rpc_create(0);
564         if (!rpc)
565                 return IFSL_MEMORY;
566
567     rpc_marshal_long(rpc, RPC_CLOSE);
568     rpc_marshal_long(rpc, fid);
569
570     rpc_queue(rpc);
571     if (!rpc_wait(rpc, RPC_TIMEOUT_LONG))
572     {
573         rpc_cancel(rpc);
574         rpt0(("cancel", "cancel close"));
575         return IFSL_RPC_TIMEOUT;
576     }
577
578     rpc_unmarshal_long(rpc, &status);
579
580     rpc_destroy(rpc);
581     return status;
582 }
583
584 uc_unlink(WCHAR *name)
585 {
586     rpc_t *rpc;
587     ULONG status;
588
589     rpc = rpc_create(0);
590         if (!rpc)
591                 return IFSL_MEMORY;
592
593     rpc_marshal_long(rpc, RPC_UNLINK);
594     rpc_marshal_wstr(rpc, name);
595
596     rpc_queue(rpc);
597     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
598     {
599         rpc_cancel(rpc);
600         rpt0(("cancel", "cancel unlink"));
601         return IFSL_RPC_TIMEOUT;
602     }
603
604     rpc_unmarshal_long(rpc, &status);
605
606     rpc_destroy(rpc);
607     return status;
608 }
609
610 uc_ioctl_write(ULONG length, char *data, ULONG *key)
611 {
612     rpc_t *rpc;
613     ULONG status;
614
615     rpc = rpc_create(0);
616         if (!rpc)
617                 return IFSL_MEMORY;
618
619     rpc_marshal_long(rpc, RPC_IOCTL_WRITE);
620     rpc_marshal_long(rpc, length);
621
622     rpc_queue_bulk(rpc, data, length, NULL, 0);
623     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
624     {
625         rpc_cancel(rpc);
626         rpt0(("cancel", "cancel ioctl write"));
627         return IFSL_RPC_TIMEOUT;
628     }
629
630     rpc_unmarshal_long(rpc, &status);
631     rpc_unmarshal_long(rpc, key);
632
633     rpc_destroy(rpc);
634     return status;
635 }
636
637 uc_ioctl_read(ULONG key, ULONG *length, char *data)
638 {
639     rpc_t *rpc;
640     ULONG status;
641
642     rpc = rpc_create(0);
643         if (!rpc)
644                 return IFSL_MEMORY;
645
646     rpc_marshal_long(rpc, RPC_IOCTL_READ);
647     rpc_marshal_long(rpc, key);
648
649     rpc_queue_bulk(rpc, NULL, 0, data, *length);
650     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
651     {
652         rpc_cancel(rpc);
653         rpt0(("cancel", "cancel ioctl read"));
654         return IFSL_RPC_TIMEOUT;
655     }
656
657     rpc_unmarshal_long(rpc, &status);
658     rpc_unmarshal_long(rpc, length);
659
660     rpc_destroy(rpc);
661     return status;
662 }
663
664 uc_rename(ULONG fid, WCHAR *curr, WCHAR *new_dir, WCHAR *new_name, ULONG *new_fid)
665 {
666     rpc_t *rpc;
667     ULONG status;
668
669     rpc = rpc_create(0);
670     if (!rpc)
671         return IFSL_MEMORY;
672
673     rpc_marshal_long(rpc, RPC_RENAME);
674     rpc_marshal_long(rpc, fid);
675     rpc_marshal_wstr(rpc, curr);
676     rpc_marshal_wstr(rpc, new_dir);
677     rpc_marshal_wstr(rpc, new_name);
678
679     rpc_queue(rpc);
680     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
681     {
682         rpc_cancel(rpc);
683         rpt0(("cancel", "cancel rename"));
684         return IFSL_RPC_TIMEOUT;
685     }
686
687     rpc_unmarshal_long(rpc, &status);
688     rpc_unmarshal_long(rpc, new_fid);
689
690     rpc_destroy(rpc);
691     return status;
692 }
693
694 uc_flush(ULONG fid)
695 {
696     rpc_t *rpc;
697     ULONG status;
698
699     rpc = rpc_create(0);
700     if (!rpc)
701         return IFSL_MEMORY;
702
703     rpc_marshal_long(rpc, RPC_FLUSH);
704     rpc_marshal_long(rpc, fid);
705
706     rpc_queue(rpc);
707     if (!rpc_wait(rpc, RPC_TIMEOUT_LONG))
708     {
709         rpc_cancel(rpc);
710         rpt0(("cancel", "cancel flush"));
711         return IFSL_RPC_TIMEOUT;
712     }
713
714     rpc_unmarshal_long(rpc, &status);
715
716     rpc_destroy(rpc);
717     return status;
718 }
719 #endif
720
721
722 /* downcall stubs */
723 #ifndef RPC_KERN
724 dc_break_callback(ULONG fid)
725 {
726     rpc_t *rpc;
727     ULONG status;
728
729     rpc = rpc_create(0);
730         if (!rpc)
731                 return IFSL_MEMORY;
732
733     rpc_marshal_long(rpc, RPC_BREAK_CALLBACK);
734     rpc_marshal_long(rpc, fid);
735     if (!rpc_transact(rpc))
736     {
737         rpc_destroy(rpc);
738         return IFSL_GENERIC_FAILURE;
739     }
740     rpc_unmarshal_long(rpc, &status);
741     rpc_destroy(rpc);
742     return status;
743 }
744
745 dc_release_hooks()
746 {
747     rpc_t *rpc;
748     ULONG status;
749
750     rpc = rpc_create(0);
751         if (!rpc)
752                 return IFSL_MEMORY;
753
754     rpc_marshal_long(rpc, RPC_RELEASE_HOOKS);
755     if (!rpc_transact(rpc))
756     {
757         rpc_destroy(rpc);
758         return IFSL_GENERIC_FAILURE;
759     }
760     rpc_unmarshal_long(rpc, &status);
761     rpc_destroy(rpc);
762     return status;
763 }
764 #endif
765
766
767 /* rpc packing function */
768 rpc_marshal_long(rpc_t *rpc, ULONG data)
769 {
770     memcpy(rpc->out_pos, &data, sizeof(ULONG));
771     rpc->out_pos += sizeof(ULONG);
772     return 0;
773 }
774
775 rpc_marshal_longlong(rpc_t *rpc, LARGE_INTEGER data)
776 {
777     memcpy(rpc->out_pos, &data, sizeof(LARGE_INTEGER));
778     rpc->out_pos += sizeof(LARGE_INTEGER);
779     return 0;
780 }
781
782 rpc_marshal_wstr(rpc_t *rpc, WCHAR *str)
783 {
784     long len;
785     len = wcslen(str);
786     rpc_marshal_long(rpc, len);
787     memcpy(rpc->out_pos, str, len*sizeof(WCHAR));
788     rpc->out_pos += len*sizeof(WCHAR);
789     return 0;
790 }
791
792
793 rpc_unmarshal_long(rpc_t *rpc, ULONG *data)
794 {
795     memcpy(data, rpc->in_pos, sizeof(ULONG));
796     rpc->in_pos += sizeof(ULONG);
797     return 0;
798 }
799
800 rpc_unmarshal_longlong(rpc_t *rpc, LARGE_INTEGER *data)
801 {
802     memcpy(data, rpc->in_pos, sizeof(LARGE_INTEGER));
803     rpc->in_pos += sizeof(LARGE_INTEGER);
804     return 0;
805 }
806
807 rpc_unmarshal_wstr(rpc_t *rpc, WCHAR *str)//, int len)
808 {
809     long len;
810     rpc_unmarshal_long(rpc, &len);
811     memcpy(str, rpc->in_pos, len*sizeof(WCHAR));
812     rpc->in_pos += len*sizeof(WCHAR);
813     str[len] = L'\0';
814     return 0;
815 }
816
817
818 /* kernel-queue management functions */
819 #ifdef RPC_KERN
820 rpc_t *rpc_find(int id)
821 {
822     rpc_t *curr;
823
824     curr = rpc_list_head;
825     while (curr)
826     {
827         /* dead rpc structs should not be returned */
828         if (curr->key == id && curr->status != 0)
829             return curr;
830         curr = curr->next;
831     }
832     return NULL;
833 }
834
835 rpc_t *rpc_upgrade(rpc_t *rpc, int old_status, int new_status)
836 {
837     rpc_t *curr;
838
839     if (rpc)
840     {
841         ASSERT(!old_status || rpc_find(rpc->key));
842         if (old_status != -1 && rpc->status != old_status)
843             return NULL;
844         curr = rpc;
845     }
846     else
847     {
848         curr = rpc_list_head;
849         while (curr)
850         {
851             if (old_status == -1 || curr->status == old_status)
852                 break;
853             curr = curr->next;
854         }
855     }
856
857     if (!curr)
858         return NULL;
859
860     ASSERT(old_status == -1 || curr->status == old_status);
861     curr->status = new_status;
862
863     return curr;
864 }
865
866 rpc_queue(rpc_t *rpc)
867 {
868     int ret;
869
870     ifs_lock_rpcs();
871
872     KeInitializeEvent(&rpc->ev, NotificationEvent, FALSE);
873     ret = (rpc_upgrade(rpc, 1, 2) != NULL);
874     KeSetEvent(&comExt->outEvent, 0, FALSE);
875
876     ifs_unlock_rpcs();
877
878     return ret;
879 }
880
881 rpc_cancel(rpc_t *rpc)
882 {
883     rpc_destroy(rpc);
884 }
885
886 rpc_shutdown()
887 {
888     rpc_t *curr, *next;
889
890     ifs_lock_rpcs();
891
892     curr = rpc_list_head;
893     while (curr)
894     {
895         next = curr->next;
896         ExFreePoolWithTag(curr, 0x1234);
897         num_rpcs--;
898         curr = next;
899     }
900     rpc_list_head = NULL;
901
902     ifs_unlock_rpcs();
903 }
904
905 rpc_wait(rpc_t *rpc, BOOLEAN long_op)
906 {
907     NTSTATUS ret;
908     LARGE_INTEGER timeout;
909
910     if (long_op)
911         timeout.QuadPart = -600000000L;         /* 60 seconds 60L*10000000L */
912     else
913         timeout.QuadPart = -200000000L;         /* 20 seconds 20L*10000000L */
914
915     do
916         ret = KeWaitForSingleObject(&rpc->ev, Executive, KernelMode, FALSE, &timeout);
917     while (ret != STATUS_SUCCESS && ret != STATUS_TIMEOUT);
918
919     ifs_lock_rpcs();
920     if (rpc->status == 2 ||                     /* still queued */
921         rpc->status == 5)                       /* send cancelled by library */
922         {
923         ifs_unlock_rpcs();
924         return 0;
925         }
926
927     ifs_unlock_rpcs();    
928     if (ret == STATUS_SUCCESS)
929         return 1;
930     return 0;
931 }
932
933 rpc_queue_bulk(rpc_t *rpc, char *out_bulk, ULONG out_len, char *in_bulk, ULONG in_len)
934 {
935     rpc->bulk_out = out_bulk;
936     *rpc->bulk_out_len = out_len;
937     rpc->bulk_in = in_bulk;
938     rpc->bulk_in_max = in_len;
939     return rpc_queue(rpc);
940 }
941
942 rpc_get_len(rpc_t *rpc)
943 {
944     if (*rpc->bulk_out_len != 0xFFFFFFFC)
945         return rpc->out_pos - rpc->out_buf + *rpc->bulk_out_len + sizeof(ULONG);
946     else
947         return rpc->out_pos - rpc->out_buf + sizeof(ULONG);
948 }
949
950 rpc_send(char *out_buf, int out_len, int *out_written)
951 {
952     rpc_t *rpc;
953     int ret, mdl;
954     ULONG header_len;
955
956   restart:
957
958     ifs_lock_rpcs();
959     rpc = rpc_upgrade(NULL, 2, 3);
960
961     if (!rpc)
962     {
963         ifs_unlock_rpcs();
964         return 0;
965     }
966
967     if (rpc_get_len(rpc) > out_len)
968     {
969         ifs_unlock_rpcs();
970         rpt0(("cancel", "cancel on send"));
971         rpc_upgrade(rpc, -1, 5);
972         KeSetEvent(&rpc->ev, IO_NETWORK_INCREMENT, FALSE);
973         goto restart;
974     }
975
976     header_len = rpc->out_pos - rpc->out_buf;
977     RtlCopyMemory(out_buf, rpc->out_buf, header_len);
978
979     if (*rpc->bulk_out_len && rpc->bulk_out)
980         RtlCopyMemory(out_buf + header_len, rpc->bulk_out, *rpc->bulk_out_len);
981     *out_written = header_len + *rpc->bulk_out_len;
982
983     ifs_unlock_rpcs();
984     return (*out_written != 0);
985 }
986 #endif
987
988
989 /* rpc library api */
990 #ifdef RPC_KERN
991 rpc_recv(char *in_buf, ULONG len)
992 {
993     ULONG key, header_size;
994     char *alloc;
995     rpc_t *rpc;
996
997     ifs_lock_rpcs();
998
999     rpc = rpc_find(*(ULONG*)in_buf);
1000     if (!rpc)                           /* rpc was cancelled while waiting */
1001     {
1002         ifs_unlock_rpcs();
1003         return -1;
1004     }
1005
1006     alloc = rpc->in_buf;
1007     rpc->in_buf = rpc->in_pos = in_buf;
1008     rpc_unmarshal_long(rpc, &key);
1009     ASSERT(key == rpc->key);
1010     rpc_unmarshal_long(rpc, &rpc->bulk_in_len);
1011
1012     rpc->in_buf = rpc->in_pos = alloc;
1013     header_size = len - rpc->bulk_in_len;
1014     ASSERT(header_size < RPC_BUF_SIZE);
1015
1016     RtlCopyMemory(rpc->in_buf, in_buf + 2*sizeof(ULONG), header_size - 2*sizeof(ULONG));
1017     if (rpc->bulk_in_len && rpc->bulk_in)
1018     {
1019         ASSERT(rpc->bulk_in_len <= rpc->bulk_in_max);
1020         RtlCopyMemory(rpc->bulk_in, in_buf + header_size, rpc->bulk_in_len);
1021     }
1022
1023     KeSetEvent(&rpc->ev, IO_NETWORK_INCREMENT, FALSE);          /* priority boost for waiting thread */
1024     ifs_unlock_rpcs();
1025     return 0;
1026 }
1027
1028 rpc_call(ULONG in_len, char *in_buf, ULONG out_max, char *out_buf, ULONG *out_len)
1029 {
1030     long rpc_code;
1031     ULONG status;
1032     WCHAR name[1024];
1033     ULONG key, fid;
1034     LARGE_INTEGER user_id;
1035     rpc_t rpc;
1036
1037     rpc.in_buf = rpc.in_pos = in_buf;
1038     rpc.out_buf = rpc.out_pos = out_buf;
1039
1040     rpc_unmarshal_long(&rpc, &key);
1041     rpc_unmarshal_long(&rpc, &rpc_code);
1042
1043     switch (rpc_code)
1044     {
1045     case RPC_BREAK_CALLBACK:
1046         rpc_unmarshal_long(&rpc, &fid);
1047         status = dc_break_callback(fid);
1048         rpc_marshal_long(&rpc, status);
1049         break;
1050     case RPC_RELEASE_HOOKS:
1051         status = dc_release_hooks();
1052         break;
1053     }
1054     *out_len = rpc.out_pos - rpc.out_buf;
1055     return 0;
1056 }
1057 #endif
1058
1059 #ifndef RPC_KERN
1060 rpc_parse(rpc_t *rpc)
1061 {
1062     long rpc_code;
1063     ULONG status;
1064     WCHAR name[1024];
1065     ULONG key;
1066     LARGE_INTEGER user_id;
1067
1068     rpc_unmarshal_long(rpc, &key);
1069     rpc_unmarshal_long(rpc, &rpc->bulk_in_len);
1070     rpc_unmarshal_longlong(rpc, &user_id);
1071     rpc_unmarshal_long(rpc, &rpc_code);
1072
1073     ifs_ImpersonateClient(user_id);
1074
1075     rpc_marshal_long(rpc, key);
1076     rpc->bulk_out_len = (ULONG*)rpc->out_pos;
1077     rpc_marshal_long(rpc, 0);
1078
1079     switch (rpc_code)
1080     {
1081     case RPC_NAMEI:
1082         {
1083             ULONG fid, length;
1084             char *data;
1085             //rpc_unmarshal_wstr(rpc, name);
1086             rpc_unmarshal_long(rpc, &length);
1087             //data = *((char**)rpc->in_pos);
1088             data = rpc->in_pos;
1089             status = uc_namei((WCHAR*)data, &fid);
1090             //status = uc_namei(name, &fid);
1091             rpc_marshal_long(rpc, status);              
1092             rpc_marshal_long(rpc, fid);         
1093         }
1094         break;
1095     case RPC_CHECK_ACCESS:
1096         {
1097             ULONG fid, access, granted;
1098             rpc_unmarshal_long(rpc, &fid);
1099             rpc_unmarshal_long(rpc, &access);
1100             status = uc_check_access(fid, access, &granted);
1101             rpc_marshal_long(rpc, status);              
1102             rpc_marshal_long(rpc, granted);
1103         }
1104         break;
1105     case RPC_CREATE:
1106         {
1107             LARGE_INTEGER alloc;
1108             ULONG access, granted, fid, attribs;
1109             char *data;
1110
1111             rpc_unmarshal_long(rpc, &attribs);
1112             rpc_unmarshal_longlong(rpc, &alloc);
1113             rpc_unmarshal_long(rpc, &access);
1114             //rpc_unmarshal_wstr(rpc, name);
1115             data = rpc->in_pos;
1116             status = uc_create((WCHAR*)data, attribs, alloc, access, &granted, &fid);
1117             rpc_marshal_long(rpc, status);
1118             rpc_marshal_long(rpc, granted);
1119             rpc_marshal_long(rpc, fid);
1120         }
1121         break;
1122     case RPC_STAT:
1123         {
1124             ULONG fid, attribs;
1125             LARGE_INTEGER size, creation, access, change, written;
1126             rpc_unmarshal_long(rpc, &fid);
1127             status = uc_stat(fid, &attribs, &size, &creation, &access, &change, &written);
1128             rpc_marshal_long(rpc, status);
1129             rpc_marshal_long(rpc, attribs);
1130             rpc_marshal_longlong(rpc, size);
1131             rpc_marshal_longlong(rpc, creation);
1132             rpc_marshal_longlong(rpc, access);
1133             rpc_marshal_longlong(rpc, change);
1134             rpc_marshal_longlong(rpc, written);
1135         }
1136         break;
1137     case RPC_READ:
1138         {
1139             ULONG fid, length, read;
1140             LARGE_INTEGER offset;
1141             char *data, *save;
1142             rpc_unmarshal_long(rpc, &fid);
1143             rpc_unmarshal_longlong(rpc, &offset);
1144             rpc_unmarshal_long(rpc, &length);
1145             save = rpc->out_pos;
1146             rpc_marshal_long(rpc, 0);
1147             rpc_marshal_long(rpc, 0);
1148             data = rpc->out_pos;
1149             rpc->out_pos = save;
1150             status = uc_read(fid, offset, length, &read, data);
1151             rpc_marshal_long(rpc, status);
1152             rpc_marshal_long(rpc, read);
1153             rpc->out_pos += read;
1154             *rpc->bulk_out_len = read;
1155         }
1156         break;
1157     case RPC_WRITE:
1158         {
1159             ULONG fid, length, written;
1160             LARGE_INTEGER offset;
1161             char *data;
1162             rpc_unmarshal_long(rpc, &fid);
1163             rpc_unmarshal_longlong(rpc, &offset);
1164             rpc_unmarshal_long(rpc, &length);
1165             data = rpc->in_pos;
1166             status = uc_write(fid, offset, length, &written, data);
1167             rpc_marshal_long(rpc, status);
1168             rpc_marshal_long(rpc, written);
1169         }
1170         break;
1171     case RPC_TRUNC:
1172         {
1173             ULONG fid;
1174             LARGE_INTEGER size;
1175             rpc_unmarshal_long(rpc, &fid);
1176             rpc_unmarshal_longlong(rpc, &size);
1177             status = uc_trunc(fid, size);
1178             rpc_marshal_long(rpc, status);
1179         }
1180         break;
1181     case RPC_SETINFO:
1182         {
1183             ULONG fid, attribs;
1184             LARGE_INTEGER creation, access, change, written;
1185             rpc_unmarshal_long(rpc, &fid);
1186             rpc_unmarshal_long(rpc, &attribs);
1187             rpc_unmarshal_longlong(rpc, &creation);
1188             rpc_unmarshal_longlong(rpc, &access);
1189             rpc_unmarshal_longlong(rpc, &change);
1190             rpc_unmarshal_longlong(rpc, &written);
1191             status = uc_setinfo(fid, attribs, creation, access, change, written);
1192             rpc_marshal_long(rpc, status);
1193         }
1194         break;
1195     case RPC_READDIR:
1196         {
1197             ULONG fid, count, len;
1198             LARGE_INTEGER cookie_in;
1199             char *data, *save;
1200             rpc_unmarshal_long(rpc, &fid);
1201             rpc_unmarshal_longlong(rpc, &cookie_in);
1202             rpc_unmarshal_wstr(rpc, name);
1203             rpc_unmarshal_long(rpc, &len);
1204             save = rpc->out_pos;
1205             rpc_marshal_long(rpc, 0);
1206             rpc_marshal_long(rpc, 0);
1207             rpc_marshal_long(rpc, 0);
1208             data = rpc->out_pos;
1209             rpc->out_pos = save;
1210             status = uc_readdir(fid, cookie_in, name, &count, data, &len);
1211             rpc_marshal_long(rpc, status);
1212             rpc_marshal_long(rpc, count);
1213             rpc_marshal_long(rpc, len);
1214             rpc->out_pos += len;
1215             *rpc->bulk_out_len = len;
1216         }
1217         break;
1218     case RPC_CLOSE:
1219         {
1220             ULONG fid;
1221             rpc_unmarshal_long(rpc, &fid);
1222             status = uc_close(fid);
1223             rpc_marshal_long(rpc, status);
1224         }
1225         break;
1226     case RPC_UNLINK:
1227         {
1228             ULONG fid, unlink;
1229             rpc_unmarshal_wstr(rpc, name);
1230             status = uc_unlink(name);
1231             rpc_marshal_long(rpc, status);
1232         }
1233         break;
1234     case RPC_IOCTL_WRITE:
1235         {
1236             ULONG length, key;
1237             rpc_unmarshal_long(rpc, &length);
1238             status = uc_ioctl_write(length, rpc->in_pos, &key);
1239             rpc_marshal_long(rpc, status);
1240             rpc_marshal_long(rpc, key);
1241         }
1242         break;
1243     case RPC_IOCTL_READ:
1244         {
1245             ULONG key, length;
1246             char *save, *data;
1247             rpc_unmarshal_long(rpc, &key);
1248             save = rpc->out_pos;
1249             rpc_marshal_long(rpc, 0);
1250             rpc_marshal_long(rpc, 0);
1251             data = rpc->out_pos;
1252             rpc->out_pos = save;
1253             status = uc_ioctl_read(key, &length, data);
1254             rpc_marshal_long(rpc, status);
1255             rpc_marshal_long(rpc, length);
1256             rpc->out_pos += length;
1257             *rpc->bulk_out_len = length;
1258         }
1259         break;
1260     case RPC_RENAME:
1261         {
1262             ULONG fid, new_fid;
1263             WCHAR curr[1024], new_dir[1024], new_name[1024];
1264             rpc_unmarshal_long(rpc, &fid);
1265             rpc_unmarshal_wstr(rpc, curr);
1266             rpc_unmarshal_wstr(rpc, new_dir);
1267             rpc_unmarshal_wstr(rpc, new_name);
1268             status = uc_rename(fid, curr, new_dir, new_name, &new_fid);
1269             rpc_marshal_long(rpc, status);
1270             rpc_marshal_long(rpc, new_fid);
1271         }
1272         break;
1273     case RPC_FLUSH:
1274         {
1275             ULONG fid;
1276             rpc_unmarshal_long(rpc, &fid);
1277             status = uc_flush(fid);
1278             rpc_marshal_long(rpc, status);
1279         }
1280         break;
1281     }
1282 }
1283 #endif