xref: /plan9/sys/src/cmd/aquarela/smbcomopen.c (revision 3e5d0078acdadead679c94c0daec143041c4b41e)
1 #include "headers.h"
2 
3 static void
smblogprintattr(int cmd,ushort attr)4 smblogprintattr(int cmd, ushort attr)
5 {
6 	if (attr & SMB_ATTR_READ_ONLY)
7 		smblogprint(cmd, " readonly");
8 	if (attr & SMB_ATTR_HIDDEN)
9 		smblogprint(cmd, " hidden");
10 	if (attr & SMB_ATTR_SYSTEM)
11 		smblogprint(cmd, " system");
12 	if (attr & SMB_ATTR_DIRECTORY)
13 		smblogprint(cmd, " directory");
14 	if (attr & SMB_ATTR_ARCHIVE)
15 		smblogprint(cmd, " archive");
16 }
17 
18 static SmbFile *
openfile(SmbSession * s,SmbTree * t,char * path,ushort mode,ushort attr,ushort ofun,ulong createoptions,uvlong createsize,ushort * fidp,Dir ** dp,ushort * actionp)19 openfile(SmbSession *s, SmbTree *t, char *path, ushort mode, ushort attr, ushort ofun, ulong createoptions, uvlong createsize,
20 	ushort *fidp, Dir **dp, ushort *actionp)
21 {
22 	int p9mode;
23 	int share;
24 	Dir *d = nil;
25 	int fd = -1;
26 	ushort action;
27 	SmbFile *f = nil;
28 	SmbSharedFile *sf = nil;
29 	char *fullpath = nil;
30 	int diropen = 0;
31 
32 //smblogprint(-1, "%s A %r", path);
33 	p9mode = (mode >> SMB_OPEN_MODE_ACCESS_SHIFT) & SMB_OPEN_MODE_ACCESS_MASK;
34 	share = (mode >> SMB_OPEN_MODE_SHARE_SHIFT) & SMB_OPEN_MODE_SHARE_MASK;
35 	if (share == SMB_OPEN_MODE_SHARE_COMPATIBILITY) {
36 	badshare:
37 //smblogprint(-1, "%s SMB_OPEN_MODE_SHARE_COMPATIBILITY", path);
38 		smbseterror(s, ERRDOS, ERRbadshare);
39 		goto done;
40 	}
41 	smbstringprint(&fullpath, "%s%s", t->serv->path, path);
42 	d = dirstat(fullpath);
43 	if (d) {
44 		/* file exists */
45 		int ofunexist;
46 		if (d->mode & DMDIR) {
47 			if (createoptions & SMB_CO_FILE) {
48 				smbseterror(s, ERRDOS, ERRnoaccess);
49 				goto done;
50 			}
51 		}
52 		else if (createoptions & SMB_CO_DIRECTORY) {
53 			smbseterror(s, ERRDOS, ERRnoaccess);
54 			goto done;
55 		}
56 
57 		sf = smbsharedfileget(d, p9mode, &share);
58 		if (sf == nil)
59 			goto badshare;
60 		action = 1;
61 		ofunexist = (ofun >> SMB_OFUN_EXIST_SHIFT) & SMB_OFUN_EXIST_MASK;
62 		if (ofunexist == SMB_OFUN_EXIST_FAIL) {
63 			smbseterror(s, ERRDOS, ERRfilexists);
64 			goto done;
65 		}
66 		else if (ofunexist == SMB_OFUN_EXIST_TRUNCATE) {
67 			if ((d->mode & DMDIR) || (p9mode != OWRITE && p9mode != ORDWR)) {
68 				smbseterror(s, ERRDOS, ERRbadaccess);
69 				goto done;
70 			}
71 			p9mode |= OTRUNC;
72 			action = 3;
73 		}
74 		else if (ofunexist != SMB_OFUN_EXIST_OPEN) {
75 			smbseterror(s, ERRDOS, ERRbadaccess);
76 			goto done;
77 		}
78 		if (d->mode & DMDIR)
79 			diropen = 1;
80 		else
81 			fd = open(fullpath, p9mode);
82 	}
83 	else {
84 		/* file does not exist */
85 		ulong p9attr;
86 		action = 3;
87 		if ((ofun & SMB_OFUN_NOEXIST_CREATE) == 0) {
88 			smbseterror(s, ERRDOS, ERRbadfile);
89 			goto done;
90 		}
91 		if (createsize != 0) {
92 			smbseterror(s, ERRDOS, ERRunsup);
93 			goto done;
94 		}
95 //smblogprint(-1, "creating: attr 0x%.4ux co 0x%.8lux\n", attr, createoptions);
96 		if (createoptions & SMB_CO_FILE) {
97 			attr &= SMB_ATTR_DIRECTORY;
98 			if (attr == 0)
99 				attr = SMB_ATTR_NORMAL;
100 		}
101 		else if (createoptions & SMB_CO_DIRECTORY) {
102 			attr &= ~SMB_ATTR_NORMAL;
103 			attr |= SMB_ATTR_DIRECTORY;
104 			p9mode = OREAD;
105 		}
106 //smblogprint(-1, "creating: before conversion attr 0x%.4ux\n", attr);
107 		p9attr = smbdosattr2plan9mode(attr);
108 //smblogprint(-1, "creating: after conversion p9attr 0%.uo\n", p9attr);
109 		fd = create(fullpath, p9mode, p9attr);
110 		if (fd >= 0) {
111 			d = dirfstat(fd);
112 			sf = smbsharedfileget(d, p9mode, &share);
113 			if (sf == nil) {
114 				close(fd);
115 				remove(path);
116 				goto badshare;
117 			}
118 		}
119 	}
120 //smblogprint(-1, "%s D %r", fullpath);
121 	if (!diropen && fd < 0) {
122 		smbseterror(s, ERRSRV, ERRaccess);
123 		goto done;
124 	}
125 	f = smbemalloc(sizeof(SmbFile));
126 	if (diropen) {
127 		f->ioallowed = 0;
128 		f->fd = -1;
129 	}
130 	else {
131 		f->ioallowed = 1;
132 		f->fd = fd;
133 	}
134 	f->name = smbestrdup(path);
135 	f->sf = sf;
136 	sf = nil;
137 	f->share = share;
138 	f->p9mode = p9mode;
139 	f->t = t;
140 	if (s->fidmap == nil)
141 		s->fidmap = smbidmapnew();
142 	*fidp = smbidmapadd(s->fidmap, f);
143 //smblogprint(h->command, "REPLY:\n t->id=0x%ux fid=%d path=%s\n", t->id, *fidp, path);
144 	smblogprintif(smbglobals.log.fids, "openfile: 0x%.4ux/0x%.4ux %s\n", t->id, *fidp, path);
145 	if (actionp)
146 		*actionp = action;
147 	if (dp) {
148 		*dp = d;
149 		d = nil;
150 	}
151 done:
152 	if (sf)
153 		smbsharedfileput(nil, sf, share);
154 	free(d);
155 	free(fullpath);
156 	return f;
157 }
158 
159 SmbProcessResult
smbcomopenandx(SmbSession * s,SmbHeader * h,uchar * pdata,SmbBuffer * b)160 smbcomopenandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
161 {
162 	uchar andxcommand;
163 	ushort andxoffset, flags, mode, sattr, attr;
164 	ulong createtime;
165 	ushort ofun;
166 	ulong createsize, timeout;
167 	char *path = nil;
168 	ulong andxoffsetfixupoffset;
169 	SmbProcessResult pr;
170 	ushort action;
171 	Dir *d = nil;
172 	SmbFile *f;
173 	SmbTree *t;
174 	ushort fid;
175 
176 	if (!smbcheckwordcount("comopenandx", h, 15))
177 		return SmbProcessResultFormat;
178 
179 	andxcommand = *pdata++;
180 	pdata++;
181 	andxoffset = smbnhgets(pdata); pdata += 2;
182 	flags = smbnhgets(pdata); pdata += 2;
183 	mode = smbnhgets(pdata); pdata += 2;
184 	sattr = smbnhgets(pdata); pdata += 2;
185 	attr = smbnhgets(pdata); pdata += 2;
186 	createtime = smbnhgetl(pdata); pdata += 4;
187 	ofun = smbnhgets(pdata); pdata += 2;
188 	createsize = smbnhgetl(pdata); pdata += 4;
189 	timeout = smbnhgetl(pdata); pdata += 4;
190 	pdata += 4;
191 	USED(pdata);
192 	if (!smbbuffergetstring(b, h, SMB_STRING_PATH, &path)) {
193 		pr = SmbProcessResultFormat;
194 		goto done;
195 	}
196 
197 	smbloglock();
198 	smblogprint(h->command, "flags 0x%.4ux", flags);
199 	if (flags & SMB_OPEN_FLAGS_ADDITIONAL)
200 		smblogprint(h->command, " additional");
201 	if (flags & SMB_OPEN_FLAGS_OPLOCK)
202 		smblogprint(h->command, " oplock");
203 	if (flags & SMB_OPEN_FLAGS_OPBATCH)
204 		smblogprint(h->command, " opbatch");
205 	smblogprint(h->command, "\n");
206 	smblogprint(h->command, "mode 0x%.4ux", mode);
207 	switch ((mode >> SMB_OPEN_MODE_ACCESS_SHIFT) & SMB_OPEN_MODE_ACCESS_MASK) {
208 	case OREAD:
209 		smblogprint(h->command, " OREAD");
210 		break;
211 	case OWRITE:
212 		smblogprint(h->command, " OWRITE");
213 		break;
214 	case ORDWR:
215 		smblogprint(h->command, " ORDWR");
216 		break;
217 	case OEXEC:
218 		smblogprint(h->command, " OEXEC");
219 		break;
220 	}
221 	switch ((mode >> SMB_OPEN_MODE_SHARE_SHIFT) & SMB_OPEN_MODE_SHARE_MASK) {
222 	case SMB_OPEN_MODE_SHARE_COMPATIBILITY:
223 		smblogprint(h->command, " compatinility");
224 		break;
225 	case SMB_OPEN_MODE_SHARE_EXCLUSIVE:
226 		smblogprint(h->command, " exclusive");
227 		break;
228 	case SMB_OPEN_MODE_SHARE_DENY_WRITE:
229 		smblogprint(h->command, " deny write");
230 		break;
231 	case SMB_OPEN_MODE_SHARE_DENY_READOREXEC:
232 		smblogprint(h->command, " deny readorxec");
233 		break;
234 	case SMB_OPEN_MODE_SHARE_DENY_NONE:
235 		smblogprint(h->command, " deny none");
236 		break;
237 	}
238 	if (mode & SMB_OPEN_MODE_WRITE_THROUGH)
239 		smblogprint(h->command, " write through");
240 	smblogprint(h->command, "\n");
241 	smblogprint(h->command, "sattr 0x%.4ux", sattr);
242 	smblogprintattr(h->command, sattr);
243 	smblogprint(h->command, "\n");
244 	smblogprint(h->command, "attr 0x%.4ux", attr);
245 	smblogprintattr(h->command, attr);
246 	smblogprint(h->command, "\n");
247 	smblogprint(h->command, "createtime 0x%.8lux\n", createtime);
248 	smblogprint(h->command, "ofun 0x%.4ux", ofun);
249 	if (ofun & SMB_OFUN_NOEXIST_CREATE)
250 		smblogprint(h->command, " noexistscreate");
251 	else
252 		smblogprint(h->command, " noexistfail");
253 	switch ((ofun >> SMB_OFUN_EXIST_SHIFT) & SMB_OFUN_EXIST_MASK) {
254 	case SMB_OFUN_EXIST_FAIL:
255 		smblogprint(h->command, " existfail");
256 		break;
257 	case SMB_OFUN_EXIST_OPEN:
258 		smblogprint(h->command, " existopen");
259 		break;
260 	case SMB_OFUN_EXIST_TRUNCATE:
261 		smblogprint(h->command, " existtruncate");
262 		break;
263 	}
264 	smblogprint(h->command, "\n");
265 	smblogprint(h->command, "createsize 0x%.8lux\n", createsize);
266 	smblogprint(h->command, "timeout 0x%.8lux\n", timeout);
267 	smblogprint(h->command, "path %s\n", path);
268 	smblogunlock();
269 
270 	t = smbidmapfind(s->tidmap, h->tid);
271 	if (t == nil) {
272 		smbseterror(s, ERRSRV, ERRinvtid);
273 		goto errordone;
274 	}
275 
276 	f = openfile(s, t, path, mode, attr, ofun, 0, createsize, &fid, &d, &action);
277 	if (f == nil) {
278 		pr = SmbProcessResultError;
279 		goto done;
280 	}
281 	h->wordcount = 15;
282 	if (!smbbufferputandxheader(s->response, h, &s->peerinfo, andxcommand, &andxoffsetfixupoffset)
283 		|| !smbbufferputs(s->response, fid)
284 		|| !smbbufferputs(s->response, smbplan9mode2dosattr(d->mode))
285 		|| !smbbufferputl(s->response, smbplan9time2utime(d->mtime, s->tzoff))
286 		|| !smbbufferputl(s->response, smbplan9length2size32(d->length))
287 		|| !smbbufferputs(s->response, smbplan9mode2dosattr(d->mode)) // probbaly bogus
288 		|| !smbbufferputs(s->response, 0)	// all files are files
289 		|| !smbbufferputs(s->response, 0)	// pipe state
290 		|| !smbbufferputs(s->response, action)
291 		|| !smbbufferputl(s->response, 0)	// fileID
292 		|| !smbbufferputs(s->response, 0)
293 		|| !smbbufferputs(s->response, 0)) {	// bytecount 0
294 		smbfileclose(s, f);
295 		pr = SmbProcessResultMisc;
296 		goto done;
297 	}
298 	if (andxcommand != SMB_COM_NO_ANDX_COMMAND)
299 		pr = smbchaincommand(s, h, andxoffsetfixupoffset, andxcommand, andxoffset, b);
300 	else
301 		pr = SmbProcessResultReply;
302 	goto done;
303 errordone:
304 	pr = SmbProcessResultError;
305 done:
306 	free(path);
307 	free(d);
308 	return pr;
309 }
310 
311 SmbProcessResult
smbcomopen(SmbSession * s,SmbHeader * h,uchar * pdata,SmbBuffer * b)312 smbcomopen(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
313 {
314 	uchar fmt;
315 	char *path;
316 	ushort mode, attr;
317 	SmbTree *t;
318 	ushort fid;
319 	Dir *d = nil;
320 	SmbFile *f;
321 	SmbProcessResult pr;
322 
323 	if (!smbcheckwordcount("comopen", h, 2))
324 		return SmbProcessResultFormat;
325 	mode = smbnhgets(pdata);
326 	attr = smbnhgets(pdata + 2);
327 	if (!smbbuffergetb(b, &fmt)
328 		|| fmt != 4
329 		|| !smbbuffergetstring(b, h, SMB_STRING_PATH, &path)) {
330 		pr = SmbProcessResultFormat;
331 		goto done;
332 	}
333 	t = smbidmapfind(s->tidmap, h->tid);
334 	if (t == nil) {
335 		smbseterror(s, ERRSRV, ERRinvtid);
336 	error:
337 		pr = SmbProcessResultError;
338 		goto done;
339 	}
340 	f = openfile(s, t, path, mode, attr,
341 		SMB_OFUN_EXIST_OPEN << SMB_OFUN_EXIST_SHIFT,
342 		0, 0, &fid, &d, nil);
343 	if (f == nil)
344 		goto error;
345 	h->wordcount = 7;
346 	if (!smbbufferputheader(s->response, h, &s->peerinfo)
347 		|| !smbbufferputs(s->response, fid)
348 		|| !smbbufferputs(s->response, smbplan9mode2dosattr(d->mode))
349 		|| !smbbufferputl(s->response, smbplan9time2utime(d->mtime, s->tzoff))
350 		|| !smbbufferputl(s->response, smbplan9length2size32(d->length))
351 		|| !smbbufferputs(s->response, 2)		// lies - this should be the actual access allowed
352 		|| !smbbufferputs(s->response, 0))
353 		pr = SmbProcessResultMisc;
354 	else
355 		pr = SmbProcessResultReply;
356 done:
357 	free(path);
358 	free(d);
359 	return pr;
360 }
361 
362 
363 /*
364    smb_com      SMBcreate       smb_com      SMBcreate
365    smb_wct      3               smb_wct      1
366    smb_vwv[0]   attribute       smb_vwv[0]   file handle
367    smb_vwv[1]   time low        smb_bcc      0
368    smb_vwv[2]   time high
369    smb_bcc      min = 2
370    smb_buf[]    ASCII -- 04
371                 file pathname
372 */
373 
374 SmbProcessResult
smbcomcreate(SmbSession * s,SmbHeader * h,uchar * pdata,SmbBuffer * b)375 smbcomcreate(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
376 {
377 	int ofun, attr, mode;
378 	long createtime;
379 	char *path;
380 	uchar fmt;
381 	SmbFile *f;
382 	SmbTree *t;
383 	ushort fid;
384 	SmbProcessResult pr;
385 
386 	path = nil;
387 	if (!smbcheckwordcount("comcreate", h, 3))
388 		return SmbProcessResultFormat;
389 
390 	smblogprint(h->command, "tid=%d\n", h->tid);
391 	attr = smbnhgets(pdata); pdata += 2;
392 	createtime = smbnhgetl(pdata);
393 	if (!smbbuffergetb(b, &fmt) || fmt != 0x04 ||
394 	    !smbbuffergetstring(b, h, SMB_STRING_PATH, &path)){
395 		pr = SmbProcessResultError;
396 		goto done;
397 	}
398 
399 	smbloglock();
400 	smblogprint(h->command, "path %s\n", path);
401 	smblogprint(h->command, "attr 0x%.4ux", attr);
402 	smblogprintattr(h->command, attr);
403 	smblogprint(h->command, "\n");
404 	smblogprint(h->command, "createtime 0x%.8lux\n", createtime);
405 	smblogunlock();
406 
407 	t = smbidmapfind(s->tidmap, h->tid);
408 	if (t == nil) {
409 		pr = SmbProcessResultError;
410 		goto done;
411 	}
412 
413 	mode = (ORDWR<<SMB_OPEN_MODE_ACCESS_SHIFT) | // SFS: FIXME: should be OWRITE?
414 		(SMB_OPEN_MODE_SHARE_EXCLUSIVE<<SMB_OPEN_MODE_SHARE_SHIFT);
415 	ofun = SMB_OFUN_NOEXIST_CREATE|(SMB_OFUN_EXIST_FAIL<<SMB_OFUN_EXIST_SHIFT);
416 	f = openfile(s, t, path, mode, attr, ofun, SMB_CO_FILE, 0, &fid, nil, nil);
417 	if (f == nil) {
418 		pr = SmbProcessResultError;
419 		goto done;
420 	}
421 
422 	h->wordcount = 1;		// SFS: FIXME: unsure of this constant, maybe should be 3
423 	if (!smbbufferputheader(s->response, h, &s->peerinfo)
424 		|| !smbbufferputs(s->response, fid)
425 		|| !smbbufferputs(s->response, 0)){	// bytecount 0
426 		pr = SmbProcessResultMisc;
427 		goto done;
428 	}
429 	pr = SmbProcessResultReply;
430 	goto done;
431 
432 done:
433 	free(path);
434 	return pr;
435 }
436 
437 
438 typedef struct SmbSblut {
439 	char *s;
440 	ulong mask;
441 } SmbSblut;
442 
443 static SmbSblut dasblut[] = {
444 	{ "SMB_DA_SPECIFIC_READ_DATA", SMB_DA_SPECIFIC_READ_DATA },
445 	{ "SMB_DA_SPECIFIC_WRITE_DATA", SMB_DA_SPECIFIC_WRITE_DATA },
446 	{ "SMB_DA_SPECIFIC_APPEND_DATA", SMB_DA_SPECIFIC_APPEND_DATA },
447 	{ "SMB_DA_SPECIFIC_READ_EA", SMB_DA_SPECIFIC_READ_EA },
448 	{ "SMB_DA_SPECIFIC_WRITE_EA", SMB_DA_SPECIFIC_WRITE_EA },
449 	{ "SMB_DA_SPECIFIC_EXECUTE", SMB_DA_SPECIFIC_EXECUTE },
450 	{ "SMB_DA_SPECIFIC_DELETE_CHILD", SMB_DA_SPECIFIC_DELETE_CHILD },
451 	{ "SMB_DA_SPECIFIC_READ_ATTRIBUTES", SMB_DA_SPECIFIC_READ_ATTRIBUTES },
452 	{ "SMB_DA_SPECIFIC_WRITE_ATTRIBUTES", SMB_DA_SPECIFIC_WRITE_ATTRIBUTES },
453 	{ "SMB_DA_STANDARD_DELETE_ACCESS", SMB_DA_STANDARD_DELETE_ACCESS },
454 	{ "SMB_DA_STANDARD_READ_CONTROL_ACCESS", SMB_DA_STANDARD_READ_CONTROL_ACCESS },
455 	{ "SMB_DA_STANDARD_WRITE_DAC_ACCESS", SMB_DA_STANDARD_WRITE_DAC_ACCESS },
456 	{ "SMB_DA_STANDARD_WRITE_OWNER_ACCESS", SMB_DA_STANDARD_WRITE_OWNER_ACCESS },
457 	{ "SMB_DA_STANDARD_SYNCHRONIZE_ACCESS", SMB_DA_STANDARD_SYNCHRONIZE_ACCESS },
458 	{ "SMB_DA_GENERIC_ALL_ACCESS", SMB_DA_GENERIC_ALL_ACCESS },
459 	{ "SMB_DA_GENERIC_EXECUTE_ACCESS", SMB_DA_GENERIC_EXECUTE_ACCESS },
460 	{ "SMB_DA_GENERIC_WRITE_ACCESS", SMB_DA_GENERIC_WRITE_ACCESS },
461 	{ "SMB_DA_GENERIC_READ_ACCESS", SMB_DA_GENERIC_READ_ACCESS },
462 	{ 0 }
463 };
464 
465 static SmbSblut efasblut[] = {
466 	{ "SMB_ATTR_READ_ONLY", SMB_ATTR_READ_ONLY },
467 	{ "SMB_ATTR_HIDDEN", SMB_ATTR_HIDDEN },
468 	{ "SMB_ATTR_SYSTEM", SMB_ATTR_SYSTEM },
469 	{ "SMB_ATTR_DIRECTORY", SMB_ATTR_DIRECTORY },
470 	{ "SMB_ATTR_ARCHIVE", SMB_ATTR_ARCHIVE },
471 	{ "SMB_ATTR_NORMAL", SMB_ATTR_NORMAL },
472 	{ "SMB_ATTR_COMPRESSED", SMB_ATTR_COMPRESSED },
473 	{ "SMB_ATTR_TEMPORARY", SMB_ATTR_TEMPORARY },
474 	{ "SMB_ATTR_WRITETHROUGH", SMB_ATTR_WRITETHROUGH },
475 	{ "SMB_ATTR_NO_BUFFERING", SMB_ATTR_NO_BUFFERING },
476 	{ "SMB_ATTR_RANDOM_ACCESS", SMB_ATTR_RANDOM_ACCESS },
477 	{ 0 }
478 };
479 
480 static SmbSblut sasblut[] = {
481 	{ "SMB_SA_SHARE_READ", SMB_SA_SHARE_READ },
482 	{ "SMB_SA_SHARE_WRITE", SMB_SA_SHARE_WRITE },
483 	{ "SMB_SA_SHARE_DELETE", SMB_SA_SHARE_DELETE },
484 	{ "SMB_SA_NO_SHARE", SMB_SA_NO_SHARE },
485 	{ 0 }
486 };
487 
488 static SmbSblut cosblut[] = {
489 	{ "SMB_CO_DIRECTORY", SMB_CO_DIRECTORY },
490 	{ "SMB_CO_WRITETHROUGH", SMB_CO_WRITETHROUGH },
491 	{ "SMB_CO_SEQUENTIAL_ONLY", SMB_CO_SEQUENTIAL_ONLY },
492 	{ "SMB_CO_FILE", SMB_CO_FILE },
493 	{ "SMB_CO_NO_EA_KNOWLEDGE", SMB_CO_NO_EA_KNOWLEDGE },
494 	{ "SMB_CO_EIGHT_DOT_THREE_ONLY", SMB_CO_EIGHT_DOT_THREE_ONLY },
495 	{ "SMB_CO_RANDOM_ACCESS", SMB_CO_RANDOM_ACCESS },
496 	{ "SMB_CO_DELETE_ON_CLOSE", SMB_CO_DELETE_ON_CLOSE },
497 	{ 0 }
498 };
499 
500 static SmbSlut cdslut[] = {
501 	{ "SMB_CD_SUPERCEDE", SMB_CD_SUPERCEDE },
502 	{ "SMB_CD_OPEN", SMB_CD_OPEN },
503 	{ "SMB_CD_CREATE", SMB_CD_CREATE },
504 	{ "SMB_CD_OPEN_IF", SMB_CD_OPEN_IF },
505 	{ "SMB_CD_OVERWRITE", SMB_CD_OVERWRITE },
506 	{ "SMB_CD_OVERWRITE_IF", SMB_CD_OVERWRITE_IF },
507 	{ 0 }
508 };
509 
510 static void
smbsblutlogprint(uchar cmd,SmbSblut * sblut,ulong mask)511 smbsblutlogprint(uchar cmd, SmbSblut *sblut, ulong mask)
512 {
513 	while (sblut->s) {
514 		if (mask && (sblut->mask & mask) || (mask == 0 && sblut->mask == 0))
515 			smblogprint(cmd, " %s", sblut->s);
516 		sblut++;
517 	}
518 }
519 
520 SmbProcessResult
smbcomntcreateandx(SmbSession * s,SmbHeader * h,uchar * pdata,SmbBuffer * b)521 smbcomntcreateandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
522 {
523 	uchar andxcommand;
524 	ushort andxoffset;
525 	char *path = nil;
526 	SmbProcessResult pr;
527 	ulong namelength;
528 	ulong flags;
529 	ulong rootdirectoryfid, desiredaccess;
530 	uvlong allocationsize;
531 	ulong extfileattributes, shareaccess, createdisposition, createoptions, impersonationlevel;
532 	uchar securityflags;
533 	int p9mode;
534 	int sharemode;
535 	ushort mode;
536 	SmbTree *t;
537 	ushort ofun;
538 	SmbFile *f;
539 	ushort fid;
540 	Dir *d = nil;
541 	ushort action;
542 	uvlong mtime;
543 	ulong andxoffsetfixup;
544 
545 	if (!smbcheckwordcount("comntcreateandx", h, 24))
546 		return SmbProcessResultFormat;
547 
548 	andxcommand = *pdata++;
549 	pdata++;
550 	andxoffset = smbnhgets(pdata); pdata += 2;
551 	pdata++;
552 	namelength = smbnhgets(pdata); pdata += 2;
553 	flags = smbnhgetl(pdata); pdata += 4;
554 	rootdirectoryfid = smbnhgetl(pdata); pdata += 4;
555 	desiredaccess = smbnhgetl(pdata); pdata += 4;
556 	allocationsize = smbnhgetv(pdata); pdata += 8;
557 	extfileattributes = smbnhgetl(pdata); pdata += 4;
558 	shareaccess = smbnhgetl(pdata); pdata += 4;
559 	createdisposition = smbnhgetl(pdata); pdata += 4;
560 	createoptions = smbnhgetl(pdata); pdata += 4;
561 	impersonationlevel = smbnhgetl(pdata); pdata += 4;
562 	securityflags = *pdata++;
563 	USED(pdata);
564 
565 	if (!smbbuffergetstring(b, h, SMB_STRING_PATH, &path)) {
566 		pr = SmbProcessResultFormat;
567 		goto done;
568 	}
569 
570 	smblogprint(h->command, "namelength %d\n", namelength);
571 	smblogprint(h->command, "flags 0x%.8lux\n", flags);
572 	smblogprint(h->command, "rootdirectoryfid %lud\n", rootdirectoryfid);
573 	smblogprint(h->command, "desiredaccess 0x%.8lux", desiredaccess);
574 	smbsblutlogprint(h->command, dasblut, desiredaccess);
575 	smblogprint(h->command, "\n");
576 	smblogprint(h->command, "allocationsize %llud\n", allocationsize);
577 	smblogprint(h->command, "extfileattributes 0x%.8lux", extfileattributes);
578 	smbsblutlogprint(h->command, efasblut, extfileattributes);
579 	smblogprint(h->command, "\n");
580 	smblogprint(h->command, "shareaccess 0x%.8lux", shareaccess);
581 	smbsblutlogprint(h->command, sasblut, shareaccess);
582 	smblogprint(h->command, "\n");
583 	smblogprint(h->command, "createdisposition 0x%.8lux %s\n",
584 		createdisposition, smbrevslut(cdslut, createdisposition));
585 	smblogprint(h->command, "createoptions 0x%.8lux", createoptions);
586 	smbsblutlogprint(h->command, cosblut, createoptions);
587 	smblogprint(h->command, "\n");
588 	smblogprint(h->command, "impersonationlevel 0x%.8lux\n", impersonationlevel);
589 	smblogprint(h->command, "securityflags 0x%.2ux\n", securityflags);
590 	smblogprint(h->command, "path %s\n", path);
591 
592 	if (rootdirectoryfid != 0) {
593 		smblogprint(-1, "smbcomntcreateandx: fid relative not implemented\n");
594 		goto unimp;
595 	}
596 
597 	if (desiredaccess & SMB_DA_GENERIC_MASK)
598 		switch (desiredaccess & SMB_DA_GENERIC_MASK){
599 		case SMB_DA_GENERIC_READ_ACCESS:
600 			p9mode = OREAD;
601 			break;
602 		case SMB_DA_GENERIC_WRITE_ACCESS:
603 			p9mode = OWRITE;
604 			break;
605 		case SMB_DA_GENERIC_ALL_ACCESS:
606 			p9mode = ORDWR;
607 			break;
608 		case SMB_DA_GENERIC_EXECUTE_ACCESS:
609 			p9mode = OEXEC;
610 			break;
611 		default:
612 			p9mode = OREAD;
613 			break;
614 		}
615 	else
616 	if (desiredaccess & SMB_DA_SPECIFIC_READ_DATA)
617 		if (desiredaccess & (SMB_DA_SPECIFIC_WRITE_DATA | SMB_DA_SPECIFIC_APPEND_DATA))
618 			p9mode = ORDWR;
619 		else
620 			p9mode = OREAD;
621 	else if (desiredaccess & (SMB_DA_SPECIFIC_WRITE_DATA | SMB_DA_SPECIFIC_APPEND_DATA))
622 		p9mode = ORDWR;
623 	else
624 		p9mode = OREAD;
625 
626 	if (shareaccess == SMB_SA_NO_SHARE)
627 		sharemode = SMB_OPEN_MODE_SHARE_EXCLUSIVE;
628 	else if (shareaccess & (SMB_SA_SHARE_READ | SMB_SA_SHARE_WRITE) ==
629 		(SMB_SA_SHARE_READ | SMB_SA_SHARE_WRITE))
630 		sharemode = SMB_OPEN_MODE_SHARE_DENY_NONE;
631 	else if (shareaccess & SMB_SA_SHARE_READ)
632 		sharemode = SMB_OPEN_MODE_SHARE_DENY_WRITE;
633 	else if (shareaccess & SMB_SA_SHARE_WRITE)
634 		sharemode = SMB_OPEN_MODE_SHARE_DENY_READOREXEC;
635 	else
636 		sharemode = SMB_OPEN_MODE_SHARE_DENY_NONE;
637 
638 	mode = (sharemode << SMB_OPEN_MODE_SHARE_SHIFT) | (p9mode << SMB_OPEN_MODE_ACCESS_SHIFT);
639 
640 	switch (createdisposition) {
641 	default:
642 		smblogprint(-1, "smbcomntcreateandx: createdisposition 0x%.8lux not implemented\n", createdisposition);
643 		goto unimp;
644 	case SMB_CD_OPEN:
645 		ofun = SMB_OFUN_EXIST_OPEN;
646 		break;
647 	case SMB_CD_CREATE:
648 		ofun = SMB_OFUN_EXIST_FAIL | SMB_OFUN_NOEXIST_CREATE;
649 		break;
650 	case SMB_CD_OPEN_IF:
651 		ofun = SMB_OFUN_EXIST_OPEN | SMB_OFUN_NOEXIST_CREATE;
652 		break;
653 	case SMB_CD_OVERWRITE:
654 		ofun = SMB_OFUN_EXIST_TRUNCATE;
655 		break;
656 	case SMB_CD_OVERWRITE_IF:
657 		ofun = SMB_OFUN_EXIST_TRUNCATE | SMB_OFUN_NOEXIST_CREATE;
658 		break;
659 	}
660 
661 	t = smbidmapfind(s->tidmap, h->tid);
662 	if (t == nil) {
663 		smbseterror(s, ERRSRV, ERRinvtid);
664 		pr = SmbProcessResultError;
665 		goto done;
666 	}
667 
668 	f = openfile(s, t, path, mode, extfileattributes, ofun, createoptions, allocationsize, &fid, &d, &action);
669 
670 	if (f == nil) {
671 		pr = SmbProcessResultError;
672 		goto done;
673 	}
674 
675 	h->wordcount = 42;
676 	mtime =  smbplan9time2time(d->mtime);
677 	if (!smbbufferputandxheader(s->response, h, &s->peerinfo, andxcommand, &andxoffsetfixup)
678 		|| !smbbufferputb(s->response, 0)		// oplocks? pah
679 		|| !smbbufferputs(s->response, fid)
680 		|| !smbbufferputl(s->response, action)
681 		|| !smbbufferputv(s->response, mtime)
682 		|| !smbbufferputv(s->response, smbplan9time2time(d->atime))
683 		|| !smbbufferputv(s->response, mtime)
684 		|| !smbbufferputv(s->response, mtime)
685 		|| !smbbufferputl(s->response, smbplan9mode2dosattr(d->mode))
686 		|| !smbbufferputv(s->response, smbl2roundupvlong(d->length, smbglobals.l2allocationsize))
687 		|| !smbbufferputv(s->response, d->length)
688 		|| !smbbufferputbytes(s->response, nil, 4)
689 		|| !smbbufferputb(s->response, (d->qid.type & QTDIR) != 0)
690 		|| !smbbufferputbytes(s->response, nil, 8)
691 		|| !smbbufferputs(s->response, 0)) {
692 		pr = SmbProcessResultMisc;
693 		goto done;
694 	}
695 
696 	if (andxcommand != SMB_COM_NO_ANDX_COMMAND)
697 		pr = smbchaincommand(s, h, andxoffsetfixup, andxcommand, andxoffset, b);
698 	else
699 		pr = SmbProcessResultReply;
700 
701 	goto done;
702 
703 unimp:
704 	pr = SmbProcessResultUnimp;
705 
706 done:
707 	free(path);
708 	free(d);
709 
710 	return pr;
711 }
712 
713