venus: Remove dedebug
[openafs.git] / src / WINNT / afsd / smb_rpc.c
1 /*
2  * Copyright (c) 2009 Secure Endpoints Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use, copy,
8  * modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24
25 #define SMB_RPC_IMPL
26
27 #include <afsconfig.h>
28 #include <afs/param.h>
29 #include <roken.h>
30
31 #include <afs/stds.h>
32
33 #include <windows.h>
34 #pragma warning(push)
35 #pragma warning(disable: 4005)
36 #include <ntstatus.h>
37 #pragma warning(pop)
38 #include <stdlib.h>
39 #include <string.h>
40 #include <osi.h>
41
42 #include "afsd.h"
43 #include "smb.h"
44
45 #include <strsafe.h>
46
47 /**
48    Meant to set up an endpoing by name, but only checks for a valid name
49
50    We don't bother trying to locate the endpoint here because the RPC
51    logic already does that using much more specific information than
52    just the name.
53
54  */
55 afs_int32
56 smb_RPC_SetupEndpointByname(smb_rpc_t * rpcp, const clientchar_t * epnamep)
57 {
58     const char * secondary_name = NULL;
59
60     if (!cm_ClientStrCmpI(epnamep, _C("wkssvc"))) {
61         secondary_name = ".\\PIPE\\wkssvc";
62     } else if (!cm_ClientStrCmpI(epnamep, _C("srvsvc"))) {
63         secondary_name = ".\\PIPE\\srvsvc";
64     } else {
65         return CM_ERROR_NOSUCHPATH;
66     }
67
68     return MSRPC_InitConn(&rpcp->rpc_conn, secondary_name);
69 }
70
71 /**
72    Setup a smb_fid:: structure for RPC
73
74    \note Obtains fidp->mx */
75 afs_int32
76 smb_SetupRPCFid(smb_fid_t * fidp, const clientchar_t * _epnamep,
77                 unsigned short * file_type,
78                 unsigned short * device_state)
79 {
80     smb_rpc_t *rpcp;
81     afs_int32 code = 0;
82     const clientchar_t * epnamep;
83
84     epnamep = cm_ClientStrChr(_epnamep, _C('\\'));
85     if (epnamep == NULL)
86         epnamep = _epnamep;
87     else
88         epnamep = cm_ClientCharNext(epnamep);
89
90     lock_ObtainMutex(&fidp->mx);
91     fidp->flags |= SMB_FID_RPC;
92     fidp->scp = &cm_data.fakeSCache;
93     cm_HoldSCache(fidp->scp);
94     if (fidp->rpcp == NULL) {
95         rpcp = malloc(sizeof(*rpcp));
96         memset(rpcp, 0, sizeof(*rpcp));
97         fidp->rpcp = rpcp;
98         rpcp->fidp = fidp;
99     } else {
100         rpcp = fidp->rpcp;
101     }
102     code = smb_RPC_SetupEndpointByname(rpcp, epnamep);
103     lock_ReleaseMutex(&fidp->mx);
104
105     if (code == 0) {
106         *file_type = SMB_FILETYPE_MESSAGE_MODE_PIPE;
107         *device_state =((0xff) |        /* instance count */
108                         SMB_DEVICESTATE_READMSGFROMPIPE |
109                         SMB_DEVICESTATE_MESSAGEMODEPIPE |
110                         SMB_DEVICESTATE_PIPECLIENTEND);
111     }
112
113     return code;
114 }
115
116 /**
117    Cleanup a smb_fid:: structure that was used for RPC
118
119    \note Called with fidp->mx locked */
120 void
121 smb_CleanupRPCFid(smb_fid_t * fidp)
122 {
123     if (fidp->rpcp)
124         MSRPC_FreeConn(&fidp->rpcp->rpc_conn);
125 }
126
127 afs_int32
128 smb_RPC_PrepareRead(smb_rpc_t * rpcp)
129 {
130     return MSRPC_PrepareRead(&rpcp->rpc_conn);
131 }
132
133 afs_int32
134 smb_RPC_PrepareWrite(smb_rpc_t * rpcp)
135 {
136     return 0;
137 }
138
139 afs_int32
140 smb_RPC_ReadPacketLength(smb_rpc_t * rpcp, afs_uint32 max_length)
141 {
142     return MSRPC_ReadMessageLength(&rpcp->rpc_conn, max_length);
143 }
144
145 afs_int32
146 smb_RPC_ReadPacket(smb_rpc_t * rpcp, BYTE * buffer, afs_uint32 length)
147 {
148     osi_Log1(smb_logp, "   RPC Read Packet for length %d", length);
149     return MSRPC_ReadMessage(&rpcp->rpc_conn, buffer, length);
150 }
151
152 afs_int32
153 smb_RPC_WritePacket(smb_rpc_t * rpcp, BYTE * buffer, afs_uint32 length,
154                     cm_user_t * userp)
155 {
156     return MSRPC_WriteMessage(&rpcp->rpc_conn, buffer, length, userp);
157 }
158
159 /*! \brief Begin an RPC operation
160
161   While generally we receive RPC requests one at a time, we have to
162   protect against receiving multiple requests in parallel since
163   there's nothing really preventing that from happening.
164
165   This should be called before calling any of the smb_RPC_*()
166   functions.  If the return value is non-zero, it should be considered
167   unsafe to call any smb_RPC_*() function.
168
169   Each successful call to smb_RPC_BeginOp() should be coupled with a
170   call to smb_RPC_EndOp().
171
172   \note Should be called with rpcp->fidp->mx locked.
173  */
174 afs_int32
175 smb_RPC_BeginOp(smb_rpc_t * rpcp)
176 {
177     if (rpcp == NULL)
178         return CM_ERROR_INVAL;
179
180     osi_assertx(rpcp->fidp, "No fidp assigned to smb_rpc_t");
181     lock_AssertMutex(&rpcp->fidp->mx);
182
183     while (rpcp->fidp->flags & SMB_FID_RPC_INCALL) {
184         osi_SleepM((LONG_PTR) rpcp, &rpcp->fidp->mx);
185         lock_ObtainMutex(&rpcp->fidp->mx);
186     }
187
188     rpcp->fidp->flags |= SMB_FID_RPC_INCALL;
189     return 0;
190 }
191
192 /*! \brief End an RPC operation
193
194   \see smb_RPC_BeginOp()
195  */
196 afs_int32
197 smb_RPC_EndOp(smb_rpc_t * rpcp)
198 {
199     lock_ObtainMutex(&rpcp->fidp->mx);
200     osi_assertx(rpcp->fidp->flags & SMB_FID_RPC_INCALL, "RPC_EndOp() call without RPC_BeginOp()");
201     rpcp->fidp->flags &= ~SMB_FID_RPC_INCALL;
202     lock_ReleaseMutex(&rpcp->fidp->mx);
203
204     osi_Wakeup((LONG_PTR) rpcp);
205
206     return 0;
207 }
208
209 /**
210    Handle a SMB_COM_READ for an RPC fid
211
212    Called from smb_ReceiveCoreRead when we receive a read on the RPC
213    fid */
214 afs_int32
215 smb_RPCRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
216 {
217     smb_rpc_t *rpcp;
218     long count;
219     char *op;
220     afs_int32 code;
221     cm_user_t *userp;
222
223     count = smb_GetSMBParm(inp, 1);
224     userp = smb_GetUserFromVCP(vcp, inp);
225
226     osi_Log3(smb_logp, "smb_RPCRead for user[0x%p] fid[0x%p (%d)]",
227              userp, fidp, fidp->fid);
228
229     lock_ObtainMutex(&fidp->mx);
230     rpcp = fidp->rpcp;
231     code = smb_RPC_BeginOp(rpcp);
232     lock_ReleaseMutex(&fidp->mx);
233
234     if (code) {
235         cm_ReleaseUser(userp);
236
237         return code;
238     }
239
240     code = smb_RPC_PrepareRead(rpcp);
241
242     if (code) {
243         cm_ReleaseUser(userp);
244
245         smb_RPC_EndOp(rpcp);
246
247         return code;
248     }
249
250     count = smb_RPC_ReadPacketLength(rpcp, count);
251
252     /* now set the parms for a read of count bytes */
253     smb_SetSMBParm(outp, 0, count);
254     smb_SetSMBParm(outp, 1, 0);
255     smb_SetSMBParm(outp, 2, 0);
256     smb_SetSMBParm(outp, 3, 0);
257     smb_SetSMBParm(outp, 4, 0);
258
259     smb_SetSMBDataLength(outp, count+3);
260
261     op = smb_GetSMBData(outp, NULL);
262     *op++ = 1;
263     *op++ = (char)(count & 0xff);
264     *op++ = (char)((count >> 8) & 0xff);
265
266     smb_RPC_ReadPacket(rpcp, op, count);
267
268     smb_RPC_EndOp(rpcp);
269
270     cm_ReleaseUser(userp);
271
272     return 0;
273 }
274
275 /**
276    Handle SMB_COM_WRITE for an RPC fid
277
278    Called from smb_ReceiveCoreWrite when we receive a write call on
279    the RPC file descriptor.
280  */
281 afs_int32
282 smb_RPCWrite(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
283 {
284     smb_rpc_t *rpcp;
285     long count;
286     afs_int32 code;
287     char *op;
288     int inDataBlockCount;
289     cm_user_t *userp = NULL;
290
291     code = 0;
292     count = smb_GetSMBParm(inp, 1);
293     userp = smb_GetUserFromVCP(vcp, inp);
294
295     osi_Log3(smb_logp, "smb_RPCWrite for user[0x%p] fid[0x%p (%d)]",
296              userp, fidp, fidp->fid);
297
298     if (userp == NULL) {
299         code = CM_ERROR_BADSMB;
300         goto done;
301     }
302
303     lock_ObtainMutex(&fidp->mx);
304     rpcp = fidp->rpcp;
305     code = smb_RPC_BeginOp(rpcp);
306     lock_ReleaseMutex(&fidp->mx);
307     if (code)
308         goto done;
309
310     smb_RPC_PrepareWrite(rpcp);
311
312     op = smb_GetSMBData(inp, NULL);
313     op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
314
315     code = smb_RPC_WritePacket(rpcp, op, count, userp);
316
317     smb_RPC_EndOp(rpcp);
318
319   done:
320     /* return # of bytes written */
321     if (code == 0) {
322         smb_SetSMBParm(outp, 0, count);
323         smb_SetSMBDataLength(outp, 0);
324     }
325
326     if (userp)
327         cm_ReleaseUser(userp);
328
329     return code;
330 }
331
332 /**
333    Handle SMB_COM_WRITE_ANDX for an RPC fid
334
335    Called from smb_ReceiveV3WriteX when we receive a write call on the
336    RPC file descriptor.
337  */
338 afs_int32
339 smb_RPCV3Write(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
340 {
341     smb_rpc_t *rpcp;
342     long count;
343     afs_int32 code;
344     char *op;
345     cm_user_t *userp = NULL;
346
347     code = 0;
348     count = smb_GetSMBParm(inp, 10);
349     userp = smb_GetUserFromVCP(vcp, inp);
350
351     osi_Log3(smb_logp, "smb_RPCV3Write for user[0x%p] fid[0x%p (%d)]",
352              userp, fidp, fidp->fid);
353
354     if (userp == NULL) {
355         code = CM_ERROR_BADSMB;
356         goto done;
357     }
358
359     lock_ObtainMutex(&fidp->mx);
360     rpcp = fidp->rpcp;
361     code = smb_RPC_BeginOp(rpcp);
362     lock_ReleaseMutex(&fidp->mx);
363
364     if (code)
365         goto done;
366
367     smb_RPC_PrepareWrite(rpcp);
368
369     op = inp->data + smb_GetSMBParm(inp, 11);
370
371     code = smb_RPC_WritePacket(rpcp, op, count, userp);
372
373     smb_RPC_EndOp(rpcp);
374
375   done:
376     /* return # of bytes written */
377     if (code == 0) {
378         smb_SetSMBParm(outp, 2, count);
379         smb_SetSMBParm(outp, 3, 0); /* reserved */
380         smb_SetSMBParm(outp, 4, 0); /* reserved */
381         smb_SetSMBParm(outp, 5, 0); /* reserved */
382         smb_SetSMBDataLength(outp, 0);
383     }
384
385     if (userp)
386         cm_ReleaseUser(userp);
387
388     return code;
389 }
390
391
392 /**
393    Handle SMB_COM_READ_ANDX for an RPC fid
394
395    Called from smb_ReceiveV3ReadX to handle RPC descriptor reads */
396 afs_int32
397 smb_RPCV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
398 {
399     smb_rpc_t *rpcp;
400     long count;
401     afs_int32 code;
402     char *op;
403     cm_user_t *userp;
404     smb_user_t *uidp;
405
406     count = smb_GetSMBParm(inp, 5);
407
408     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
409     if (!uidp)
410         return CM_ERROR_BADSMB;
411     userp = smb_GetUserFromUID(uidp);
412     osi_assertx(userp != NULL, "null cm_user_t");
413
414     osi_Log3(smb_logp, "smb_RPCV3Read for user[0x%p] fid[0x%p (%d)]",
415              userp, fidp, fidp->fid);
416
417     if (uidp && uidp->unp) {
418         osi_Log3(afsd_logp, "RPC uid %d user %x name %S",
419                  uidp->userID, userp,
420                  osi_LogSaveClientString(afsd_logp, uidp->unp->name));
421     } else {
422         if (uidp)
423             osi_Log2(afsd_logp, "RPC uid %d user %x no name",
424                      uidp->userID, userp);
425         else
426             osi_Log1(afsd_logp, "RPC no uid user %x no name",
427                      userp);
428     }
429
430     lock_ObtainMutex(&fidp->mx);
431     rpcp = fidp->rpcp;
432     code = smb_RPC_BeginOp(rpcp);
433     lock_ReleaseMutex(&fidp->mx);
434
435     if (code) {
436         if (uidp)
437             smb_ReleaseUID(uidp);
438         cm_ReleaseUser(userp);
439         return code;
440     }
441
442     code = smb_RPC_PrepareRead(rpcp);
443     if (uidp) {
444         smb_ReleaseUID(uidp);
445     }
446     if (code) {
447         cm_ReleaseUser(userp);
448         smb_RPC_EndOp(rpcp);
449         return code;
450     }
451
452     count = smb_RPC_ReadPacketLength(rpcp, count);
453
454     /* 0 and 1 are reserved for request chaining, were setup by our caller,
455      * and will be further filled in after we return.
456      */
457     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
458     smb_SetSMBParm(outp, 3, 0); /* resvd */
459     smb_SetSMBParm(outp, 4, 0); /* resvd */
460     smb_SetSMBParm(outp, 5, count);     /* # of bytes we're going to read */
461     /* fill in #6 when we have all the parameters' space reserved */
462     smb_SetSMBParm(outp, 7, 0); /* resv'd */
463     smb_SetSMBParm(outp, 8, 0); /* resv'd */
464     smb_SetSMBParm(outp, 9, 0); /* resv'd */
465     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
466     smb_SetSMBParm(outp, 11, 0);        /* reserved */
467
468     /* get op ptr after putting in the last parm, since otherwise we don't
469      * know where the data really is.
470      */
471     op = smb_GetSMBData(outp, NULL);
472
473     /* now fill in offset from start of SMB header to first data byte (to op) */
474     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
475
476     /* set the packet data length the count of the # of bytes */
477     smb_SetSMBDataLength(outp, count);
478
479     smb_RPC_ReadPacket(rpcp, op, count);
480
481     smb_RPC_EndOp(rpcp);
482
483     /* and cleanup things */
484     cm_ReleaseUser(userp);
485
486     return 0;
487 }
488
489 afs_int32
490 smb_RPCNmpipeTransact(smb_fid_t *fidp, smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
491 {
492     smb_tran2Packet_t *outp = NULL;
493     struct smb_rpc *rpcp;
494     afs_int32 code = 0;
495     cm_user_t * userp = NULL;
496     smb_user_t * uidp = NULL;
497     int len;
498
499     osi_Log0(smb_logp, "smb_RPCNmpipeTransact() begin");
500
501     uidp = smb_FindUID(vcp, p->uid, 0);
502     if (!uidp)
503         return CM_ERROR_BADSMB;
504     userp = smb_GetUserFromUID(uidp);
505     osi_assertx(userp != NULL, "null cm_user_t");
506
507     if (uidp && uidp->unp) {
508         osi_Log3(afsd_logp, "RPC Transact uid %d user %x name %S",
509                  uidp->userID, userp,
510                  osi_LogSaveClientString(afsd_logp, uidp->unp->name));
511     } else {
512         if (uidp)
513             osi_Log2(afsd_logp, "RPC Transact uid %d user %x no name",
514                      uidp->userID, userp);
515         else
516             osi_Log1(afsd_logp, "RPC Transact no uid user %x no name",
517                      userp);
518     }
519
520     lock_ObtainMutex(&fidp->mx);
521     rpcp = fidp->rpcp;
522     code = smb_RPC_BeginOp(rpcp);
523
524     if (code) {
525         osi_Log0(smb_logp, "Can't begin RPC op.  Aborting");
526         lock_ReleaseMutex(&fidp->mx);
527
528         smb_ReleaseUID(uidp);
529         cm_ReleaseUser(userp);
530         return code;
531     }
532
533     osi_assertx((fidp->flags & SMB_FID_RPC), "FID wasn't setup for RPC");
534     osi_assertx(fidp->rpcp, "smb_rpc_t not associated with RPC FID");
535
536     lock_ReleaseMutex(&fidp->mx);
537
538     code = smb_RPC_PrepareWrite(rpcp);
539     if (code)
540         goto done;
541
542     code = smb_RPC_WritePacket(rpcp, p->datap, p->totalData, userp);
543     if (code)
544         goto done;
545
546     code = smb_RPC_PrepareRead(rpcp);
547     if (code)
548         goto done;
549
550     len = smb_RPC_ReadPacketLength(rpcp, p->maxReturnData);
551
552     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, len);
553     if (len > 0) {
554         code = smb_RPC_ReadPacket(rpcp, outp->datap, len);
555
556         if (code == CM_ERROR_RPC_MOREDATA) {
557             outp->error_code = CM_ERROR_RPC_MOREDATA;
558         }
559     }
560
561     if (code == 0 || code == CM_ERROR_RPC_MOREDATA)
562         smb_SendTran2Packet(vcp, outp, op);
563     smb_FreeTran2Packet(outp);
564
565  done:
566     smb_RPC_EndOp(rpcp);
567
568     osi_Log1(smb_logp, "smb_RPCNmpipeTransact() end code=%d", code);
569
570     if (uidp)
571         smb_ReleaseUID(uidp);
572     if (userp)
573         cm_ReleaseUser(userp);
574
575     return code;
576 }