smbcommon.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. #include "headers.h"
  2. int
  3. smbsendunicode(SmbPeerInfo *i)
  4. {
  5. return smbglobals.unicode && (i == nil || (i->capabilities & CAP_UNICODE) != 0);
  6. }
  7. int
  8. smbcheckwordcount(char *name, SmbHeader *h, ushort wordcount)
  9. {
  10. if (h->wordcount != wordcount) {
  11. smblogprint(-1, "smb%s: word count not %ud\n", name, wordcount);
  12. return 0;
  13. }
  14. return 1;
  15. }
  16. int
  17. smbcheckwordandbytecount(char *name, SmbHeader *h, ushort wordcount, uchar **bdatap, uchar **edatap)
  18. {
  19. ushort bytecount;
  20. uchar *bdata;
  21. if (h->wordcount != wordcount) {
  22. smblogprint(-1, "smb%s: word count not %ud\n", name, wordcount);
  23. return 0;
  24. }
  25. bdata = *bdatap;
  26. if (bdata + 2 > *edatap) {
  27. smblogprint(-1, "smb%s: not enough data for byte count\n", name);
  28. return 0;
  29. }
  30. bytecount = smbnhgets(bdata); bdata += 2;
  31. if (bdata + bytecount > *edatap) {
  32. smblogprint(-1, "smb%s: not enough data for bytes\n", name);
  33. return 0;
  34. }
  35. *edatap = bdata + bytecount;
  36. *bdatap = bdata;
  37. return 1;
  38. }
  39. SmbProcessResult
  40. smbchaincommand(SmbSession *s, SmbHeader *h, ulong andxoffsetfixup, uchar cmd, ushort offset, SmbBuffer *b)
  41. {
  42. SmbOpTableEntry *ote;
  43. uchar *pdata;
  44. ushort bytecount;
  45. h->command = cmd;
  46. ote = smboptable + cmd;
  47. if (ote->process == nil) {
  48. smblogprint(-1, "smbchaincommand: %s (0x%.2ux) not implemented\n", ote->name, cmd);
  49. return SmbProcessResultUnimp;
  50. }
  51. if (!smbresponsealignl2(s, 2)
  52. || !smbresponseoffsetputs(s, andxoffsetfixup, smbresponseoffset(s))
  53. || !smbbufferpopreadlimit(b))
  54. return SmbProcessResultMisc;
  55. if (!smbbufferreadskipto(b, offset)) {
  56. smblogprint(-1, "smbchaincommand: illegal offset\n");
  57. return SmbProcessResultFormat;
  58. }
  59. if (!smbbuffergetb(b, &h->wordcount)) {
  60. smblogprint(-1, "smbchaincommand: not enough space for wordcount\n");
  61. return SmbProcessResultFormat;
  62. }
  63. pdata = smbbufferreadpointer(b);
  64. if (!smbbuffergetbytes(b, nil, h->wordcount * 2)) {
  65. smblogprint(-1, "smbchaincommand: not enough space for parameters\n");
  66. return SmbProcessResultFormat;
  67. }
  68. if (!smbbuffergets(b, &bytecount)) {
  69. smblogprint(-1, "smbchaincommand: not enough space for bytecount\n");
  70. return SmbProcessResultFormat;
  71. }
  72. if (!smbbufferpushreadlimit(b, smbbufferreadoffset(b) + bytecount)) {
  73. smblogprint(-1, "smbchaincommand: not enough space for bytes\n");
  74. return SmbProcessResultFormat;
  75. }
  76. smblogprint(cmd, "chaining to %s\n", ote->name);
  77. return (*ote->process)(s, h, pdata, b);
  78. }
  79. int
  80. smbbuffergetheader(SmbBuffer *b, SmbHeader *h, uchar **parametersp, ushort *bytecountp)
  81. {
  82. SmbOpTableEntry *ote;
  83. SmbRawHeader *rh;
  84. rh = (SmbRawHeader *)smbbufferreadpointer(b);
  85. if (!smbbuffergetbytes(b, nil, (long)offsetof(SmbRawHeader, parameterwords[0]))) {
  86. smblogprint(-1, "smbgetheader: short packet\n");
  87. return 0;
  88. }
  89. if (rh->protocol[0] != 0xff || memcmp(rh->protocol + 1, "SMB", 3) != 0) {
  90. smblogprint(-1, "smbgetheader: invalid protocol\n");
  91. return 0;
  92. }
  93. h->command = rh->command;
  94. ote = smboptable + h->command;
  95. if (ote->name == nil) {
  96. smblogprint(-1, "smbgetheader: illegal opcode 0x%.2ux\n", h->command);
  97. return 0;
  98. }
  99. h->errclass = rh->status[0];
  100. h->error = smbnhgets(rh->status + 2);
  101. h->flags = rh->flags;
  102. h->flags2 = smbnhgets(rh->flags2);
  103. if (h->flags & ~(SmbHeaderFlagCaseless | SMB_FLAGS_SERVER_TO_REDIR | SmbHeaderFlagReserved | SmbHeaderFlagServerIgnore))
  104. smblogprint(-1, "smbgetheader: warning: unexpected flags 0x%.2ux\n", h->flags);
  105. h->wordcount = rh->wordcount;
  106. if (parametersp)
  107. *parametersp = smbbufferreadpointer(b);
  108. if (!smbbuffergetbytes(b, nil, h->wordcount * 2)) {
  109. smblogprint(-1, "smbgetheader: not enough data for parameter words\n");
  110. return 0;
  111. }
  112. h->tid = smbnhgets(rh->tid);
  113. h->pid = smbnhgets(rh->pid);
  114. h->uid = smbnhgets(rh->uid);
  115. h->mid = smbnhgets(rh->mid);
  116. if (!smbbuffergets(b, bytecountp))
  117. *bytecountp = 0;
  118. if (!smbbufferpushreadlimit(b, smbbufferreadoffset(b) + *bytecountp))
  119. return 0;
  120. smblogprint(h->command, "%s %s: tid 0x%.4ux pid 0x%.4ux uid 0x%.4ux mid 0x%.4ux\n", ote->name,
  121. (h->flags & SMB_FLAGS_SERVER_TO_REDIR) ? "response" : "request", h->tid, h->pid, h->uid, h->mid);
  122. return 1;
  123. }
  124. int
  125. smbcheckheaderdirection(SmbHeader *h, int response, char **errmsgp)
  126. {
  127. if (((h->flags & SMB_FLAGS_SERVER_TO_REDIR) == 0) == response) {
  128. smbstringprint(errmsgp, "unexpected %s", response ? "request" : "response");
  129. return 0;
  130. }
  131. return 1;
  132. }
  133. int
  134. smbcheckheader(SmbHeader *h, uchar command, int response, char **errmsgp)
  135. {
  136. if (response && h->command != command) {
  137. smbstringprint(errmsgp, "sent %.2uc request, got %.2ux response", command, h->command);
  138. return 0;
  139. }
  140. if (!smbcheckheaderdirection(h, response, errmsgp))
  141. return 0;
  142. return 1;
  143. }
  144. int
  145. smbbuffergetandcheckheader(SmbBuffer *b, SmbHeader *h, uchar command, int response, uchar **pdatap, ushort *bytecountp, char **errmsgp)
  146. {
  147. if (!smbbuffergetheader(b, h, pdatap, bytecountp)) {
  148. smbstringprint(errmsgp, "smbbuffergetandcheckheader: not enough data for header");
  149. return 0;
  150. }
  151. return smbcheckheader(h, command, response, errmsgp);
  152. }
  153. int
  154. smbsuccess(SmbHeader *h, char **errmsgp)
  155. {
  156. if (h->errclass != SUCCESS) {
  157. smbstringprint(errmsgp, "%s returned error %d/%d", smboptable[h->command].name, h->errclass, h->error);
  158. return 0;
  159. }
  160. return 1;
  161. }
  162. #define BASE_FLAGS (0)
  163. int
  164. smbbufferputheader(SmbBuffer *b, SmbHeader *h, SmbPeerInfo *p)
  165. {
  166. SmbRawHeader *rh;
  167. if (offsetof(SmbRawHeader, parameterwords[0]) > smbbufferwritespace(b))
  168. return 0;
  169. if (smbbufferwriteoffset(b) == 0) {
  170. rh = (SmbRawHeader *)smbbufferwritepointer(b);
  171. rh->protocol[0] = 0xff;
  172. memcpy(rh->protocol + 1, "SMB", 3);
  173. rh->flags = SMB_FLAGS_SERVER_TO_REDIR | SmbHeaderFlagCaseless;
  174. rh->command = h->command;
  175. smbhnputs(rh->flags2, BASE_FLAGS | (smbsendunicode(p) ? SMB_FLAGS2_UNICODE : 0));
  176. memset(rh->extra, 0, sizeof(rh->extra));
  177. if (!smbbufferputbytes(b, nil, offsetof(SmbRawHeader, parameterwords[0])))
  178. return 0;
  179. rh->wordcount = h->wordcount;
  180. }
  181. else {
  182. rh = (SmbRawHeader *)smbbufferreadpointer(b);
  183. smbbufferputb(b, h->wordcount);
  184. }
  185. rh->status[0] = h->errclass;
  186. rh->status[1] = 0;
  187. smbhnputs(rh->status + 2, h->error);
  188. smbhnputs(rh->tid, h->tid);
  189. smbhnputs(rh->pid, h->pid);
  190. smbhnputs(rh->uid, h->uid);
  191. smbhnputs(rh->mid, h->mid);
  192. return 1;
  193. }
  194. int
  195. smbbufferputerror(SmbBuffer *s, SmbHeader *h, SmbPeerInfo *p, uchar errclass, ushort error)
  196. {
  197. h->errclass = errclass;
  198. h->error = error;
  199. return smbbufferputheader(s, h, p);
  200. }
  201. int
  202. smbbufferputandxheader(SmbBuffer *b, SmbHeader *h, SmbPeerInfo *p, uchar andxcommand, ulong *andxoffsetfixupp)
  203. {
  204. if (!smbbufferputheader(b, h, p)
  205. || !smbbufferputb(b, andxcommand)
  206. || !smbbufferputb(b, 0))
  207. return 0;
  208. *andxoffsetfixupp = smbbufferwriteoffset(b);
  209. return smbbufferputbytes(b, nil, 2);
  210. }
  211. void
  212. smbseterror(SmbSession *s, uchar errclass, ushort error)
  213. {
  214. s->errclass = errclass;
  215. s->error = error;
  216. }
  217. SmbProcessResult
  218. smbbufferputack(SmbBuffer *b, SmbHeader *h, SmbPeerInfo *p)
  219. {
  220. h->wordcount = 0;
  221. return smbbufferputheader(b, h, p) && smbbufferputs(b, 0) ? SmbProcessResultReply : SmbProcessResultMisc;
  222. }
  223. ushort
  224. smbplan9mode2dosattr(ulong mode)
  225. {
  226. if (mode & DMDIR)
  227. return SMB_ATTR_DIRECTORY;
  228. return SMB_ATTR_NORMAL;
  229. }
  230. ulong
  231. smbdosattr2plan9mode(ushort attr)
  232. {
  233. ulong mode = 0444;
  234. if ((attr & SMB_ATTR_READ_ONLY) == 0)
  235. mode |= 0222;
  236. if (attr & SMB_ATTR_DIRECTORY) {
  237. mode |= DMDIR | 0711;
  238. mode &= DMDIR | 0755;
  239. }
  240. else
  241. mode &= 0744;
  242. return mode;
  243. }
  244. ulong
  245. smbdosattr2plan9wstatmode(ulong oldmode, ushort attr)
  246. {
  247. ulong mode;
  248. if (oldmode & DMDIR)
  249. attr |= SMB_ATTR_DIRECTORY;
  250. else
  251. attr &= ~SMB_ATTR_DIRECTORY;
  252. mode = smbdosattr2plan9mode(attr);
  253. if (oldmode & 0444)
  254. mode = (mode & ~0444) | (mode & 0444);
  255. if ((attr & SMB_ATTR_READ_ONLY) == 0)
  256. mode |= oldmode & 0222;
  257. if (mode == oldmode)
  258. mode = 0xffffffff;
  259. return mode;
  260. }
  261. ulong
  262. smbplan9length2size32(vlong length)
  263. {
  264. if (length > 0xffffffff)
  265. return 0xffffffff;
  266. return length;
  267. }
  268. vlong
  269. smbl2roundupvlong(vlong v, int l2)
  270. {
  271. ulong mask;
  272. mask = (1 << l2) - 1;
  273. return (v + mask) & ~mask;
  274. }
  275. SmbSlut smbsharemodeslut[] = {
  276. { "compatibility", SMB_OPEN_MODE_SHARE_COMPATIBILITY },
  277. { "exclusive", SMB_OPEN_MODE_SHARE_EXCLUSIVE },
  278. { "denywrite", SMB_OPEN_MODE_SHARE_DENY_WRITE },
  279. { "denyread", SMB_OPEN_MODE_SHARE_DENY_READOREXEC },
  280. { "denynone", SMB_OPEN_MODE_SHARE_DENY_NONE },
  281. { 0 }
  282. };
  283. SmbSlut smbopenmodeslut[] = {
  284. { "oread", OREAD },
  285. { "owrite", OWRITE },
  286. { "ordwr", ORDWR },
  287. { "oexec", OEXEC },
  288. { 0 }
  289. };
  290. int
  291. smbslut(SmbSlut *s, char *pat)
  292. {
  293. while (s->name) {
  294. if (cistrcmp(s->name, pat) == 0)
  295. return s->val;
  296. s++;
  297. }
  298. return -1;
  299. }
  300. char *
  301. smbrevslut(SmbSlut *s, int val)
  302. {
  303. while (s->name) {
  304. if (s->val == val)
  305. return s->name;
  306. s++;
  307. }
  308. return nil;
  309. }