windows-talocale-20060829
[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
245     size = sizeof(rpc_t) + 2*RPC_BUF_SIZE;
246     rpc = malloc(size);
247     if (!rpc)
248         osi_panic("ifs_rpc: alloc buffer", __FILE__, __LINE__);
249     memset(rpc, 0, size);
250
251     rpc->out_buf = rpc->out_pos = (char*)(rpc+1);
252     rpc->in_buf = rpc->in_pos = ((char*)(rpc+1)) + RPC_BUF_SIZE;
253
254     rpc->key = rand() + 10;
255     rpc_marshal_long(rpc, rpc->key);
256
257     return rpc;
258 }
259
260 void rpc_destroy(rpc_t *rpc)
261 {
262     if (!rpc)
263         return;
264
265     free(rpc);
266 }
267
268 rpc_transact(rpc_t *rpc)
269 {
270     ULONG header_len;
271     DWORD read = 0;
272
273     if (!rpc)
274         return IFSL_GENERIC_FAILURE;
275
276     header_len = rpc->out_pos - rpc->out_buf;
277
278     read = RPC_BUF_SIZE;
279     return ifs_TransactRpc(rpc->out_buf, header_len, rpc->in_buf, &read);
280 }
281 #endif
282
283
284 /* upcall stubs */
285 #ifdef RPC_KERN
286 long
287 uc_namei(WCHAR *name, ULONG *fid)
288 {
289     rpc_t *rpc;
290     ULONG status;
291     MDL *mdl;
292
293         /* consider putting namei cache here */
294
295     rpc = rpc_create(0);
296         if (!rpc)
297                 return IFSL_MEMORY;
298
299     rpc_marshal_long(rpc, RPC_NAMEI);
300     rpc_marshal_long(rpc, wcslen(name));
301
302     rpc_queue_bulk(rpc, (void*)name, (wcslen(name)+1)*sizeof(wchar_t), NULL, 0);
303
304     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
305     {
306         rpc_cancel(rpc);
307         rpt0(("cancel", "cancel namei"));
308         return IFSL_RPC_TIMEOUT;
309     }
310
311     rpc_unmarshal_long(rpc, &status);
312     rpc_unmarshal_long(rpc, fid);
313
314     rpc_destroy(rpc);
315     return status;
316 }
317
318 long
319 uc_check_access(ULONG fid, ULONG access, ULONG *granted)
320 {
321     rpc_t *rpc;
322     ULONG status;
323
324     rpc = rpc_create(0);
325         if (!rpc)
326                 return IFSL_MEMORY;
327
328     rpc_marshal_long(rpc, RPC_CHECK_ACCESS);
329     rpc_marshal_long(rpc, fid);
330     rpc_marshal_long(rpc, access);
331
332     rpc_queue(rpc);
333     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
334     {
335         rpc_cancel(rpc);
336         rpt0(("cancel", "cancel access"));
337         return IFSL_RPC_TIMEOUT;
338     }
339
340     rpc_unmarshal_long(rpc, &status);
341     rpc_unmarshal_long(rpc, granted);
342
343     rpc_destroy(rpc);
344     return status;
345 }
346
347 long
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 long
379 uc_stat(ULONG fid, ULONG *attribs, LARGE_INTEGER *size, LARGE_INTEGER *creation, LARGE_INTEGER *access, LARGE_INTEGER *change, LARGE_INTEGER *written)
380 {
381     rpc_t *rpc;
382     ULONG status;
383
384     rpc = rpc_create(0);
385         if (!rpc)
386                 return IFSL_MEMORY;
387
388     rpc_marshal_long(rpc, RPC_STAT);
389     rpc_marshal_long(rpc, fid);
390
391     rpc_queue(rpc);
392     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
393     {
394         rpc_cancel(rpc);
395         rpt0(("cancel", "cancel stat"));
396         return IFSL_RPC_TIMEOUT;
397     }
398
399     rpc_unmarshal_long(rpc, &status);
400     rpc_unmarshal_long(rpc, attribs);
401     rpc_unmarshal_longlong(rpc, size);
402     rpc_unmarshal_longlong(rpc, creation);
403     rpc_unmarshal_longlong(rpc, access);
404     rpc_unmarshal_longlong(rpc, change);
405     rpc_unmarshal_longlong(rpc, written);
406
407     rpc_destroy(rpc);
408     return status;
409 }
410
411 long
412 uc_setinfo(ULONG fid, ULONG attribs, LARGE_INTEGER creation, LARGE_INTEGER access, LARGE_INTEGER change, LARGE_INTEGER written)
413 {
414     rpc_t *rpc;
415     ULONG status;
416
417     rpc = rpc_create(0);
418         if (!rpc)
419                 return IFSL_MEMORY;
420
421     rpc_marshal_long(rpc, RPC_SETINFO);
422     rpc_marshal_long(rpc, fid);
423     rpc_marshal_long(rpc, attribs);
424     rpc_marshal_longlong(rpc, creation);
425     rpc_marshal_longlong(rpc, access);
426     rpc_marshal_longlong(rpc, change);
427     rpc_marshal_longlong(rpc, written);
428
429
430     rpc_queue(rpc);
431     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
432     {
433         rpc_cancel(rpc);
434         rpt0(("cancel", "cancel setinfo"));
435         return IFSL_RPC_TIMEOUT;
436     }
437
438     rpc_unmarshal_long(rpc, &status);
439
440     rpc_destroy(rpc);
441     return status;
442 }
443
444 long
445 uc_trunc(ULONG fid, LARGE_INTEGER size)
446 {
447     rpc_t *rpc;
448     ULONG status;
449
450     rpc = rpc_create(0);
451         if (!rpc)
452                 return IFSL_MEMORY;
453
454     rpc_marshal_long(rpc, RPC_TRUNC);
455     rpc_marshal_long(rpc, fid);
456     rpc_marshal_longlong(rpc, size);
457
458     rpc_queue(rpc);
459     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
460     {
461         rpc_cancel(rpc);
462         rpt0(("cancel", "cancel trunc"));
463         return IFSL_RPC_TIMEOUT;
464     }
465
466     rpc_unmarshal_long(rpc, &status);
467
468     rpc_destroy(rpc);
469     return status;
470 }
471
472 long
473 uc_read(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *read, char *data)
474 {
475     rpc_t *rpc;
476     ULONG status;
477
478     rpc = rpc_create(0);
479         if (!rpc)
480                 return IFSL_MEMORY;
481
482     rpc_marshal_long(rpc, RPC_READ);
483     rpc_marshal_long(rpc, fid);
484     rpc_marshal_longlong(rpc, offset);
485     rpc_marshal_long(rpc, length);
486
487     rpc_queue_bulk(rpc, NULL, 0, data, length);
488     if (!rpc_wait(rpc, RPC_TIMEOUT_LONG))
489     {
490         rpc_cancel(rpc);
491         rpt0(("cancel", "cancel read"));
492         return IFSL_RPC_TIMEOUT;
493     }
494
495     rpc_unmarshal_long(rpc, &status);
496     rpc_unmarshal_long(rpc, read);
497
498     rpc_destroy(rpc);
499     return status;
500 }
501
502 long
503 uc_write(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *written, char *data)
504 {
505     rpc_t *rpc;
506     ULONG status;
507
508     rpc = rpc_create(0);
509         if (!rpc)
510                 return IFSL_MEMORY;
511
512     rpc_marshal_long(rpc, RPC_WRITE);
513     rpc_marshal_long(rpc, fid);
514     rpc_marshal_longlong(rpc, offset);
515     rpc_marshal_long(rpc, length);
516
517     rpc_queue_bulk(rpc, data, length, NULL, 0);
518     if (!rpc_wait(rpc, RPC_TIMEOUT_LONG))
519     {
520         rpc_cancel(rpc);
521         rpt0(("cancel", "cancel write"));
522         return IFSL_RPC_TIMEOUT;
523     }
524
525     rpc_unmarshal_long(rpc, &status);
526     rpc_unmarshal_long(rpc, written);
527
528     rpc_destroy(rpc);
529     return status;
530 }
531
532 long
533 uc_readdir(ULONG fid, LARGE_INTEGER cookie_in, WCHAR *filter, ULONG *count, char *data, ULONG *len)
534 {
535     rpc_t *rpc;
536     ULONG status;
537
538     rpc = rpc_create(0);
539         if (!rpc)
540                 return IFSL_MEMORY;
541
542     rpc_marshal_long(rpc, RPC_READDIR);
543     rpc_marshal_long(rpc, fid);
544     rpc_marshal_longlong(rpc, cookie_in);
545     rpc_marshal_wstr(rpc, filter);
546     rpc_marshal_long(rpc, *len);
547
548     rpc_queue_bulk(rpc, NULL, 0, data, *len);
549     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
550     {
551         rpc_cancel(rpc);
552         rpt0(("cancel", "cancel readdir"));
553         return IFSL_RPC_TIMEOUT;
554     }
555
556     rpc_unmarshal_long(rpc, &status);
557     rpc_unmarshal_long(rpc, count);
558     rpc_unmarshal_long(rpc, len);
559
560     rpc_destroy(rpc);
561     return status;
562 }
563
564 long
565 uc_close(ULONG fid)
566 {
567     rpc_t *rpc;
568     ULONG status;
569
570     rpc = rpc_create(0);
571         if (!rpc)
572                 return IFSL_MEMORY;
573
574     rpc_marshal_long(rpc, RPC_CLOSE);
575     rpc_marshal_long(rpc, fid);
576
577     rpc_queue(rpc);
578     if (!rpc_wait(rpc, RPC_TIMEOUT_LONG))
579     {
580         rpc_cancel(rpc);
581         rpt0(("cancel", "cancel close"));
582         return IFSL_RPC_TIMEOUT;
583     }
584
585     rpc_unmarshal_long(rpc, &status);
586
587     rpc_destroy(rpc);
588     return status;
589 }
590
591 long
592 uc_unlink(WCHAR *name)
593 {
594     rpc_t *rpc;
595     ULONG status;
596
597     rpc = rpc_create(0);
598         if (!rpc)
599                 return IFSL_MEMORY;
600
601     rpc_marshal_long(rpc, RPC_UNLINK);
602     rpc_marshal_wstr(rpc, name);
603
604     rpc_queue(rpc);
605     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
606     {
607         rpc_cancel(rpc);
608         rpt0(("cancel", "cancel unlink"));
609         return IFSL_RPC_TIMEOUT;
610     }
611
612     rpc_unmarshal_long(rpc, &status);
613
614     rpc_destroy(rpc);
615     return status;
616 }
617
618 long
619 uc_ioctl_write(ULONG length, char *data, ULONG *key)
620 {
621     rpc_t *rpc;
622     ULONG status;
623
624     rpc = rpc_create(0);
625         if (!rpc)
626                 return IFSL_MEMORY;
627
628     rpc_marshal_long(rpc, RPC_IOCTL_WRITE);
629     rpc_marshal_long(rpc, length);
630
631     rpc_queue_bulk(rpc, data, length, NULL, 0);
632     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
633     {
634         rpc_cancel(rpc);
635         rpt0(("cancel", "cancel ioctl write"));
636         return IFSL_RPC_TIMEOUT;
637     }
638
639     rpc_unmarshal_long(rpc, &status);
640     rpc_unmarshal_long(rpc, key);
641
642     rpc_destroy(rpc);
643     return status;
644 }
645
646 long
647 uc_ioctl_read(ULONG key, ULONG *length, char *data)
648 {
649     rpc_t *rpc;
650     ULONG status;
651
652     rpc = rpc_create(0);
653         if (!rpc)
654                 return IFSL_MEMORY;
655
656     rpc_marshal_long(rpc, RPC_IOCTL_READ);
657     rpc_marshal_long(rpc, key);
658
659     rpc_queue_bulk(rpc, NULL, 0, data, *length);
660     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
661     {
662         rpc_cancel(rpc);
663         rpt0(("cancel", "cancel ioctl read"));
664         return IFSL_RPC_TIMEOUT;
665     }
666
667     rpc_unmarshal_long(rpc, &status);
668     rpc_unmarshal_long(rpc, length);
669
670     rpc_destroy(rpc);
671     return status;
672 }
673
674 long
675 uc_rename(ULONG fid, WCHAR *curr, WCHAR *new_dir, WCHAR *new_name, ULONG *new_fid)
676 {
677     rpc_t *rpc;
678     ULONG status;
679
680     rpc = rpc_create(0);
681     if (!rpc)
682         return IFSL_MEMORY;
683
684     rpc_marshal_long(rpc, RPC_RENAME);
685     rpc_marshal_long(rpc, fid);
686     rpc_marshal_wstr(rpc, curr);
687     rpc_marshal_wstr(rpc, new_dir);
688     rpc_marshal_wstr(rpc, new_name);
689
690     rpc_queue(rpc);
691     if (!rpc_wait(rpc, RPC_TIMEOUT_SHORT))
692     {
693         rpc_cancel(rpc);
694         rpt0(("cancel", "cancel rename"));
695         return IFSL_RPC_TIMEOUT;
696     }
697
698     rpc_unmarshal_long(rpc, &status);
699     rpc_unmarshal_long(rpc, new_fid);
700
701     rpc_destroy(rpc);
702     return status;
703 }
704
705 long
706 uc_flush(ULONG fid)
707 {
708     rpc_t *rpc;
709     ULONG status;
710
711     rpc = rpc_create(0);
712     if (!rpc)
713         return IFSL_MEMORY;
714
715     rpc_marshal_long(rpc, RPC_FLUSH);
716     rpc_marshal_long(rpc, fid);
717
718     rpc_queue(rpc);
719     if (!rpc_wait(rpc, RPC_TIMEOUT_LONG))
720     {
721         rpc_cancel(rpc);
722         rpt0(("cancel", "cancel flush"));
723         return IFSL_RPC_TIMEOUT;
724     }
725
726     rpc_unmarshal_long(rpc, &status);
727
728     rpc_destroy(rpc);
729     return status;
730 }
731 #endif
732
733
734 /* downcall stubs */
735 #ifndef RPC_KERN
736 long dc_break_callback(ULONG fid)
737 {
738     rpc_t *rpc;
739     ULONG status;
740
741     rpc = rpc_create(0);
742         if (!rpc)
743                 return IFSL_MEMORY;
744
745     rpc_marshal_long(rpc, RPC_BREAK_CALLBACK);
746     rpc_marshal_long(rpc, fid);
747     if (!rpc_transact(rpc))
748     {
749         rpc_destroy(rpc);
750         return IFSL_GENERIC_FAILURE;
751     }
752     rpc_unmarshal_long(rpc, &status);
753     rpc_destroy(rpc);
754     return status;
755 }
756
757 long dc_release_hooks(void)
758 {
759     rpc_t *rpc;
760     ULONG status;
761
762     rpc = rpc_create(0);
763         if (!rpc)
764                 return IFSL_MEMORY;
765
766     rpc_marshal_long(rpc, RPC_RELEASE_HOOKS);
767     if (!rpc_transact(rpc))
768     {
769         rpc_destroy(rpc);
770         return IFSL_GENERIC_FAILURE;
771     }
772     rpc_unmarshal_long(rpc, &status);
773     rpc_destroy(rpc);
774     return status;
775 }
776 #endif
777
778
779 /* rpc packing function */
780 rpc_marshal_long(rpc_t *rpc, ULONG data)
781 {
782     memcpy(rpc->out_pos, &data, sizeof(ULONG));
783     rpc->out_pos += sizeof(ULONG);
784     return 0;
785 }
786
787 rpc_marshal_longlong(rpc_t *rpc, LARGE_INTEGER data)
788 {
789     memcpy(rpc->out_pos, &data, sizeof(LARGE_INTEGER));
790     rpc->out_pos += sizeof(LARGE_INTEGER);
791     return 0;
792 }
793
794 rpc_marshal_wstr(rpc_t *rpc, WCHAR *str)
795 {
796     long len;
797     len = wcslen(str);
798     rpc_marshal_long(rpc, len);
799     memcpy(rpc->out_pos, str, len*sizeof(WCHAR));
800     rpc->out_pos += len*sizeof(WCHAR);
801     return 0;
802 }
803
804
805 rpc_unmarshal_long(rpc_t *rpc, ULONG *data)
806 {
807     memcpy(data, rpc->in_pos, sizeof(ULONG));
808     rpc->in_pos += sizeof(ULONG);
809     return 0;
810 }
811
812 rpc_unmarshal_longlong(rpc_t *rpc, LARGE_INTEGER *data)
813 {
814     memcpy(data, rpc->in_pos, sizeof(LARGE_INTEGER));
815     rpc->in_pos += sizeof(LARGE_INTEGER);
816     return 0;
817 }
818
819 rpc_unmarshal_wstr(rpc_t *rpc, WCHAR *str)//, int len)
820 {
821     long len;
822     rpc_unmarshal_long(rpc, &len);
823     memcpy(str, rpc->in_pos, len*sizeof(WCHAR));
824     rpc->in_pos += len*sizeof(WCHAR);
825     str[len] = L'\0';
826     return 0;
827 }
828
829
830 /* kernel-queue management functions */
831 #ifdef RPC_KERN
832 rpc_t *rpc_find(int id)
833 {
834     rpc_t *curr;
835
836     curr = rpc_list_head;
837     while (curr)
838     {
839         /* dead rpc structs should not be returned */
840         if (curr->key == id && curr->status != 0)
841             return curr;
842         curr = curr->next;
843     }
844     return NULL;
845 }
846
847 rpc_t *rpc_upgrade(rpc_t *rpc, int old_status, int new_status)
848 {
849     rpc_t *curr;
850
851     if (rpc)
852     {
853         ASSERT(!old_status || rpc_find(rpc->key));
854         if (old_status != -1 && rpc->status != old_status)
855             return NULL;
856         curr = rpc;
857     }
858     else
859     {
860         curr = rpc_list_head;
861         while (curr)
862         {
863             if (old_status == -1 || curr->status == old_status)
864                 break;
865             curr = curr->next;
866         }
867     }
868
869     if (!curr)
870         return NULL;
871
872     ASSERT(old_status == -1 || curr->status == old_status);
873     curr->status = new_status;
874
875     return curr;
876 }
877
878 rpc_queue(rpc_t *rpc)
879 {
880     int ret;
881
882     ifs_lock_rpcs();
883
884     KeInitializeEvent(&rpc->ev, NotificationEvent, FALSE);
885     ret = (rpc_upgrade(rpc, 1, 2) != NULL);
886     KeSetEvent(&comExt->outEvent, 0, FALSE);
887
888     ifs_unlock_rpcs();
889
890     return ret;
891 }
892
893 rpc_cancel(rpc_t *rpc)
894 {
895     rpc_destroy(rpc);
896 }
897
898 rpc_shutdown()
899 {
900     rpc_t *curr, *next;
901
902     ifs_lock_rpcs();
903
904     curr = rpc_list_head;
905     while (curr)
906     {
907         next = curr->next;
908         ExFreePoolWithTag(curr, 0x1234);
909         num_rpcs--;
910         curr = next;
911     }
912     rpc_list_head = NULL;
913
914     ifs_unlock_rpcs();
915 }
916
917 rpc_wait(rpc_t *rpc, BOOLEAN long_op)
918 {
919     NTSTATUS ret;
920     LARGE_INTEGER timeout;
921
922     if (long_op)
923         timeout.QuadPart = -600000000L;         /* 60 seconds 60L*10000000L */
924     else
925         timeout.QuadPart = -200000000L;         /* 20 seconds 20L*10000000L */
926
927     do
928         ret = KeWaitForSingleObject(&rpc->ev, Executive, KernelMode, FALSE, &timeout);
929     while (ret != STATUS_SUCCESS && ret != STATUS_TIMEOUT);
930
931     ifs_lock_rpcs();
932     if (rpc->status == 2 ||                     /* still queued */
933         rpc->status == 5)                       /* send cancelled by library */
934         {
935         ifs_unlock_rpcs();
936         return 0;
937         }
938
939     ifs_unlock_rpcs();    
940     if (ret == STATUS_SUCCESS)
941         return 1;
942     return 0;
943 }
944
945 rpc_queue_bulk(rpc_t *rpc, char *out_bulk, ULONG out_len, char *in_bulk, ULONG in_len)
946 {
947     rpc->bulk_out = out_bulk;
948     *rpc->bulk_out_len = out_len;
949     rpc->bulk_in = in_bulk;
950     rpc->bulk_in_max = in_len;
951     return rpc_queue(rpc);
952 }
953
954 rpc_get_len(rpc_t *rpc)
955 {
956     if (*rpc->bulk_out_len != 0xFFFFFFFC)
957         return rpc->out_pos - rpc->out_buf + *rpc->bulk_out_len + sizeof(ULONG);
958     else
959         return rpc->out_pos - rpc->out_buf + sizeof(ULONG);
960 }
961
962 rpc_send(char *out_buf, int out_len, int *out_written)
963 {
964     rpc_t *rpc;
965     int ret, mdl;
966     ULONG header_len;
967
968   restart:
969
970     ifs_lock_rpcs();
971     rpc = rpc_upgrade(NULL, 2, 3);
972
973     if (!rpc)
974     {
975         ifs_unlock_rpcs();
976         return 0;
977     }
978
979     if (rpc_get_len(rpc) > out_len)
980     {
981         ifs_unlock_rpcs();
982         rpt0(("cancel", "cancel on send"));
983         rpc_upgrade(rpc, -1, 5);
984         KeSetEvent(&rpc->ev, IO_NETWORK_INCREMENT, FALSE);
985         goto restart;
986     }
987
988     header_len = rpc->out_pos - rpc->out_buf;
989     RtlCopyMemory(out_buf, rpc->out_buf, header_len);
990
991     if (*rpc->bulk_out_len && rpc->bulk_out)
992         RtlCopyMemory(out_buf + header_len, rpc->bulk_out, *rpc->bulk_out_len);
993     *out_written = header_len + *rpc->bulk_out_len;
994
995     ifs_unlock_rpcs();
996     return (*out_written != 0);
997 }
998 #endif
999
1000
1001 /* rpc library api */
1002 #ifdef RPC_KERN
1003 rpc_recv(char *in_buf, ULONG len)
1004 {
1005     ULONG key, header_size;
1006     char *alloc;
1007     rpc_t *rpc;
1008
1009     ifs_lock_rpcs();
1010
1011     rpc = rpc_find(*(ULONG*)in_buf);
1012     if (!rpc)                           /* rpc was cancelled while waiting */
1013     {
1014         ifs_unlock_rpcs();
1015         return -1;
1016     }
1017
1018     alloc = rpc->in_buf;
1019     rpc->in_buf = rpc->in_pos = in_buf;
1020     rpc_unmarshal_long(rpc, &key);
1021     ASSERT(key == rpc->key);
1022     rpc_unmarshal_long(rpc, &rpc->bulk_in_len);
1023
1024     rpc->in_buf = rpc->in_pos = alloc;
1025     header_size = len - rpc->bulk_in_len;
1026     ASSERT(header_size < RPC_BUF_SIZE);
1027
1028     RtlCopyMemory(rpc->in_buf, in_buf + 2*sizeof(ULONG), header_size - 2*sizeof(ULONG));
1029     if (rpc->bulk_in_len && rpc->bulk_in)
1030     {
1031         ASSERT(rpc->bulk_in_len <= rpc->bulk_in_max);
1032         RtlCopyMemory(rpc->bulk_in, in_buf + header_size, rpc->bulk_in_len);
1033     }
1034
1035     KeSetEvent(&rpc->ev, IO_NETWORK_INCREMENT, FALSE);          /* priority boost for waiting thread */
1036     ifs_unlock_rpcs();
1037     return 0;
1038 }
1039
1040 rpc_call(ULONG in_len, char *in_buf, ULONG out_max, char *out_buf, ULONG *out_len)
1041 {
1042     long rpc_code;
1043     ULONG status;
1044     WCHAR name[1024];
1045     ULONG key, fid;
1046     LARGE_INTEGER user_id;
1047     rpc_t rpc;
1048
1049     rpc.in_buf = rpc.in_pos = in_buf;
1050     rpc.out_buf = rpc.out_pos = out_buf;
1051
1052     rpc_unmarshal_long(&rpc, &key);
1053     rpc_unmarshal_long(&rpc, &rpc_code);
1054
1055     switch (rpc_code)
1056     {
1057     case RPC_BREAK_CALLBACK:
1058         rpc_unmarshal_long(&rpc, &fid);
1059         status = dc_break_callback(fid);
1060         rpc_marshal_long(&rpc, status);
1061         break;
1062     case RPC_RELEASE_HOOKS:
1063         status = dc_release_hooks();
1064         break;
1065     }
1066     *out_len = rpc.out_pos - rpc.out_buf;
1067     return 0;
1068 }
1069 #endif
1070
1071 #ifndef RPC_KERN
1072 rpc_parse(rpc_t *rpc)
1073 {
1074     long rpc_code;
1075     ULONG status;
1076     WCHAR name[1024];
1077     ULONG key;
1078     LARGE_INTEGER user_id;
1079
1080     rpc_unmarshal_long(rpc, &key);
1081     rpc_unmarshal_long(rpc, &rpc->bulk_in_len);
1082     rpc_unmarshal_longlong(rpc, &user_id);
1083     rpc_unmarshal_long(rpc, &rpc_code);
1084
1085     ifs_ImpersonateClient(user_id);
1086
1087     rpc_marshal_long(rpc, key);
1088     rpc->bulk_out_len = (ULONG*)rpc->out_pos;
1089     rpc_marshal_long(rpc, 0);
1090
1091     switch (rpc_code)
1092     {
1093     case RPC_NAMEI:
1094         {
1095             ULONG fid, length;
1096             char *data;
1097             //rpc_unmarshal_wstr(rpc, name);
1098             rpc_unmarshal_long(rpc, &length);
1099             //data = *((char**)rpc->in_pos);
1100             data = rpc->in_pos;
1101             status = uc_namei((WCHAR*)data, &fid);
1102             //status = uc_namei(name, &fid);
1103             rpc_marshal_long(rpc, status);              
1104             rpc_marshal_long(rpc, fid);         
1105         }
1106         break;
1107     case RPC_CHECK_ACCESS:
1108         {
1109             ULONG fid, access, granted;
1110             rpc_unmarshal_long(rpc, &fid);
1111             rpc_unmarshal_long(rpc, &access);
1112             status = uc_check_access(fid, access, &granted);
1113             rpc_marshal_long(rpc, status);              
1114             rpc_marshal_long(rpc, granted);
1115         }
1116         break;
1117     case RPC_CREATE:
1118         {
1119             LARGE_INTEGER alloc;
1120             ULONG access, granted, fid, attribs;
1121             char *data;
1122
1123             rpc_unmarshal_long(rpc, &attribs);
1124             rpc_unmarshal_longlong(rpc, &alloc);
1125             rpc_unmarshal_long(rpc, &access);
1126             //rpc_unmarshal_wstr(rpc, name);
1127             data = rpc->in_pos;
1128             status = uc_create((WCHAR*)data, attribs, alloc, access, &granted, &fid);
1129             rpc_marshal_long(rpc, status);
1130             rpc_marshal_long(rpc, granted);
1131             rpc_marshal_long(rpc, fid);
1132         }
1133         break;
1134     case RPC_STAT:
1135         {
1136             ULONG fid, attribs;
1137             LARGE_INTEGER size, creation, access, change, written;
1138             rpc_unmarshal_long(rpc, &fid);
1139             status = uc_stat(fid, &attribs, &size, &creation, &access, &change, &written);
1140             rpc_marshal_long(rpc, status);
1141             rpc_marshal_long(rpc, attribs);
1142             rpc_marshal_longlong(rpc, size);
1143             rpc_marshal_longlong(rpc, creation);
1144             rpc_marshal_longlong(rpc, access);
1145             rpc_marshal_longlong(rpc, change);
1146             rpc_marshal_longlong(rpc, written);
1147         }
1148         break;
1149     case RPC_READ:
1150         {
1151             ULONG fid, length, read;
1152             LARGE_INTEGER offset;
1153             char *data, *save;
1154             rpc_unmarshal_long(rpc, &fid);
1155             rpc_unmarshal_longlong(rpc, &offset);
1156             rpc_unmarshal_long(rpc, &length);
1157             save = rpc->out_pos;
1158             rpc_marshal_long(rpc, 0);
1159             rpc_marshal_long(rpc, 0);
1160             data = rpc->out_pos;
1161             rpc->out_pos = save;
1162             status = uc_read(fid, offset, length, &read, data);
1163             rpc_marshal_long(rpc, status);
1164             rpc_marshal_long(rpc, read);
1165             rpc->out_pos += read;
1166             *rpc->bulk_out_len = read;
1167         }
1168         break;
1169     case RPC_WRITE:
1170         {
1171             ULONG fid, length, written;
1172             LARGE_INTEGER offset;
1173             char *data;
1174             rpc_unmarshal_long(rpc, &fid);
1175             rpc_unmarshal_longlong(rpc, &offset);
1176             rpc_unmarshal_long(rpc, &length);
1177             data = rpc->in_pos;
1178             status = uc_write(fid, offset, length, &written, data);
1179             rpc_marshal_long(rpc, status);
1180             rpc_marshal_long(rpc, written);
1181         }
1182         break;
1183     case RPC_TRUNC:
1184         {
1185             ULONG fid;
1186             LARGE_INTEGER size;
1187             rpc_unmarshal_long(rpc, &fid);
1188             rpc_unmarshal_longlong(rpc, &size);
1189             status = uc_trunc(fid, size);
1190             rpc_marshal_long(rpc, status);
1191         }
1192         break;
1193     case RPC_SETINFO:
1194         {
1195             ULONG fid, attribs;
1196             LARGE_INTEGER creation, access, change, written;
1197             rpc_unmarshal_long(rpc, &fid);
1198             rpc_unmarshal_long(rpc, &attribs);
1199             rpc_unmarshal_longlong(rpc, &creation);
1200             rpc_unmarshal_longlong(rpc, &access);
1201             rpc_unmarshal_longlong(rpc, &change);
1202             rpc_unmarshal_longlong(rpc, &written);
1203             status = uc_setinfo(fid, attribs, creation, access, change, written);
1204             rpc_marshal_long(rpc, status);
1205         }
1206         break;
1207     case RPC_READDIR:
1208         {
1209             ULONG fid, count, len;
1210             LARGE_INTEGER cookie_in;
1211             char *data, *save;
1212             rpc_unmarshal_long(rpc, &fid);
1213             rpc_unmarshal_longlong(rpc, &cookie_in);
1214             rpc_unmarshal_wstr(rpc, name);
1215             rpc_unmarshal_long(rpc, &len);
1216             save = rpc->out_pos;
1217             rpc_marshal_long(rpc, 0);
1218             rpc_marshal_long(rpc, 0);
1219             rpc_marshal_long(rpc, 0);
1220             data = rpc->out_pos;
1221             rpc->out_pos = save;
1222             status = uc_readdir(fid, cookie_in, name, &count, data, &len);
1223             rpc_marshal_long(rpc, status);
1224             rpc_marshal_long(rpc, count);
1225             rpc_marshal_long(rpc, len);
1226             rpc->out_pos += len;
1227             *rpc->bulk_out_len = len;
1228         }
1229         break;
1230     case RPC_CLOSE:
1231         {
1232             ULONG fid;
1233             rpc_unmarshal_long(rpc, &fid);
1234             status = uc_close(fid);
1235             rpc_marshal_long(rpc, status);
1236         }
1237         break;
1238     case RPC_UNLINK:
1239         {
1240             rpc_unmarshal_wstr(rpc, name);
1241             status = uc_unlink(name);
1242             rpc_marshal_long(rpc, status);
1243         }
1244         break;
1245     case RPC_IOCTL_WRITE:
1246         {
1247             ULONG length, key;
1248             rpc_unmarshal_long(rpc, &length);
1249             status = uc_ioctl_write(length, rpc->in_pos, &key);
1250             rpc_marshal_long(rpc, status);
1251             rpc_marshal_long(rpc, key);
1252         }
1253         break;
1254     case RPC_IOCTL_READ:
1255         {
1256             ULONG key, length;
1257             char *save, *data;
1258             rpc_unmarshal_long(rpc, &key);
1259             save = rpc->out_pos;
1260             rpc_marshal_long(rpc, 0);
1261             rpc_marshal_long(rpc, 0);
1262             data = rpc->out_pos;
1263             rpc->out_pos = save;
1264             status = uc_ioctl_read(key, &length, data);
1265             rpc_marshal_long(rpc, status);
1266             rpc_marshal_long(rpc, length);
1267             rpc->out_pos += length;
1268             *rpc->bulk_out_len = length;
1269         }
1270         break;
1271     case RPC_RENAME:
1272         {
1273             ULONG fid, new_fid;
1274             WCHAR curr[1024], new_dir[1024], new_name[1024];
1275             rpc_unmarshal_long(rpc, &fid);
1276             rpc_unmarshal_wstr(rpc, curr);
1277             rpc_unmarshal_wstr(rpc, new_dir);
1278             rpc_unmarshal_wstr(rpc, new_name);
1279             status = uc_rename(fid, curr, new_dir, new_name, &new_fid);
1280             rpc_marshal_long(rpc, status);
1281             rpc_marshal_long(rpc, new_fid);
1282         }
1283         break;
1284     case RPC_FLUSH:
1285         {
1286             ULONG fid;
1287             rpc_unmarshal_long(rpc, &fid);
1288             status = uc_flush(fid);
1289             rpc_marshal_long(rpc, status);
1290         }
1291         break;
1292     }
1293 }
1294 #endif