1 #include "headers.h"
2
3 #define INMEMORYTRUNCTHRESH (256 * 1024)
4
5 static int
dirfwstatlength(int fd,vlong offset)6 dirfwstatlength(int fd, vlong offset)
7 {
8 Dir d;
9 memset(&d, 0xff, sizeof(d));
10 d.name = d.uid = d.gid = d.muid = nil;
11 d.length = offset;
12 return dirfwstat(fd, &d);
13 }
14
15 SmbProcessResult
smbtruncatefile(SmbSession * s,SmbFile * f,vlong offset)16 smbtruncatefile(SmbSession *s, SmbFile *f, vlong offset)
17 {
18 Dir *d;
19 ulong o;
20 uchar *db = nil;
21 vlong length;
22 int rv;
23 SmbProcessResult pr;
24
25 d = dirfstat(f->fd);
26 assert(d);
27 length = d->length;
28 free(d);
29
30 if (length == offset)
31 return SmbProcessResultReply;
32
33 rv = dirfwstatlength(f->fd, offset);
34 if (rv == 0) {
35 pr = SmbProcessResultReply;
36 goto done;
37 }
38 //smblogprint(-1, "dirfwstatlength failed: %r\n");
39 if (length > offset) {
40 int nfd;
41 char *fullpath;
42 if (offset > INMEMORYTRUNCTHRESH) {
43 smblogprint(-1, "smbcomwrite: truncation beyond %lud not supported\n", offset);
44 pr = SmbProcessResultUnimp;
45 goto done;
46 }
47 db = smbemalloc(offset);
48 if (pread(f->fd, db, offset, 0) != offset) {
49 pr = SmbProcessResultMisc;
50 goto done;
51 }
52 fullpath = nil;
53 smbstringprint(&fullpath, "%s%s", f->t->serv->path, f->name);
54 nfd = open(fullpath, f->p9mode | OTRUNC);
55 free(fullpath);
56 if (nfd < 0) {
57 smbseterror(s, ERRDOS, ERRnoaccess);
58 pr = SmbProcessResultError;
59 goto done;
60 }
61 close(nfd);
62 if (pwrite(f->fd, db, offset, 0) != offset) {
63 pr = SmbProcessResultMisc;
64 goto done;
65 }
66 pr = SmbProcessResultReply;
67 }
68 else {
69 db = smbemalloc(16384);
70 memset(db, 0, 16384);
71 o = length;
72 while (o < offset) {
73 long tt = 16384;
74 if (tt > offset - o)
75 tt = offset - o;
76 if (pwrite(f->fd, db, tt, o) != tt) {
77 smbseterror(s, ERRDOS, ERRnoaccess);
78 pr = SmbProcessResultError;
79 goto done;
80 }
81 o += tt;
82 }
83 pr = SmbProcessResultReply;
84 }
85 done:
86 free(db);
87 return pr;
88 }
89
90 SmbProcessResult
smbcomwrite(SmbSession * s,SmbHeader * h,uchar * pdata,SmbBuffer * b)91 smbcomwrite(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
92 {
93 SmbTree *t;
94 SmbFile *f;
95 ushort fid;
96 ushort count;
97 ulong offset;
98 long nb;
99 ushort yacount;
100 uchar fmt;
101
102 if (h->wordcount != 5)
103 return SmbProcessResultFormat;
104
105 fid = smbnhgets(pdata); pdata += 2;
106 count = smbnhgets(pdata); pdata += 2;
107 offset = smbnhgetl(pdata);
108
109 smblogprint(SMB_COM_WRITE, "smbcomwrite: fid 0x%.4ux count 0x%.4ux offset 0x%.8lux\n",
110 fid, count, offset);
111
112 if (!smbbuffergetb(b, &fmt)
113 || fmt != 1
114 || !smbbuffergets(b, &yacount)
115 || yacount != count
116 || smbbufferreadspace(b) < count)
117 return SmbProcessResultFormat;
118
119 t = smbidmapfind(s->tidmap, h->tid);
120 if (t == nil) {
121 smbseterror(s, ERRSRV, ERRinvtid);
122 return SmbProcessResultError;
123 }
124 f = smbidmapfind(s->fidmap, fid);
125 if (f == nil) {
126 smbseterror(s, ERRDOS, ERRbadfid);
127 return SmbProcessResultError;
128 }
129
130 if (!f->ioallowed) {
131 smbseterror(s, ERRDOS, ERRbadaccess);
132 return SmbProcessResultError;
133 }
134
135 if (count == 0) {
136 SmbProcessResult pr = smbtruncatefile(s, f, offset);
137 if (pr != SmbProcessResultReply)
138 return pr;
139 nb = 0;
140 }
141 else {
142 seek(f->fd, offset, 0);
143 nb = write(f->fd, smbbufferreadpointer(b), count);
144 if (nb < 0) {
145 smbseterror(s, ERRDOS, ERRnoaccess);
146 return SmbProcessResultError;
147 }
148 }
149 h->wordcount = 1;
150 if (!smbbufferputheader(s->response, h, &s->peerinfo)
151 || !smbbufferputs(s->response, nb)
152 || !smbbufferputs(s->response, 0))
153 return SmbProcessResultMisc;
154 return SmbProcessResultReply;
155 }
156
157 SmbProcessResult
smbcomwriteandx(SmbSession * s,SmbHeader * h,uchar * pdata,SmbBuffer * b)158 smbcomwriteandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
159 {
160 uchar andxcommand;
161 ushort andxoffset;
162 ulong andxoffsetfixup;
163 SmbTree *t;
164 SmbFile *f;
165 ushort dataoff, fid, count;
166 vlong offset;
167 long nb;
168
169 if (h->wordcount != 12 && h->wordcount != 14)
170 return SmbProcessResultFormat;
171
172 andxcommand = *pdata++; // andx command
173 pdata++; // reserved
174 andxoffset = smbnhgets(pdata); pdata += 2; // andx offset
175 fid = smbnhgets(pdata); pdata += 2; // fid
176 offset = smbnhgetl(pdata); pdata += 4; // offset in file
177 pdata += 4; // timeout
178 pdata += 2; // write mode
179 pdata += 2; // (Remaining) bytes waiting to be written
180 pdata += 2; // Reserved
181 count = smbnhgets(pdata); pdata += 2; // LSBs of length
182 dataoff = smbnhgets(pdata); pdata += 2; // offset to data in packet
183 if (dataoff + count > smbbufferwriteoffset(b))
184 return SmbProcessResultFormat;
185 if(h->wordcount == 14)
186 offset |= (vlong)smbnhgetl(pdata)<<32;
187
188 smblogprint(SMB_COM_WRITE_ANDX, "smbcomwriteandx: fid 0x%.4ux count 0x%.4ux offset 0x%.llux\n",
189 fid, count, offset);
190
191
192 t = smbidmapfind(s->tidmap, h->tid);
193 if (t == nil) {
194 smbseterror(s, ERRSRV, ERRinvtid);
195 return SmbProcessResultError;
196 }
197 f = smbidmapfind(s->fidmap, fid);
198 if (f == nil) {
199 smbseterror(s, ERRDOS, ERRbadfid);
200 return SmbProcessResultError;
201 }
202
203 if (!f->ioallowed) {
204 smbseterror(s, ERRDOS, ERRbadaccess);
205 return SmbProcessResultError;
206 }
207
208 seek(f->fd, offset, 0);
209 nb = write(f->fd, smbbufferpointer(b, dataoff), count);
210 if (nb < 0) {
211 smbseterror(s, ERRDOS, ERRnoaccess);
212 return SmbProcessResultError;
213 }
214
215 h->wordcount = 6;
216 if (!smbbufferputandxheader(s->response, h, &s->peerinfo, andxcommand, &andxoffsetfixup))
217 return SmbProcessResultMisc;
218
219 if (!smbbufferputs(s->response, nb) // Count
220 || !smbbufferputs(s->response, 0) // Available
221 || !smbbufferputl(s->response, 0) // Reserved
222 || !smbbufferputs(s->response, 0)) // byte count in reply
223 return SmbProcessResultMisc;
224
225 if (andxcommand != SMB_COM_NO_ANDX_COMMAND)
226 return smbchaincommand(s, h, andxoffsetfixup, andxcommand, andxoffset, b);
227
228 return SmbProcessResultReply;
229 }
230