revert between 56095 -> 55830 in arch
[AROS.git] / workbench / network / smbfs / source_code / proc.c
blob4d426ad2626f2e4a85bffa746e4d41badcf455b5
1 /*
2 * $Id$
4 * :ts=4
6 * proc.c
8 * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
10 * 28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per
12 * Modified for big endian support by Christian Starkjohann.
13 * Modified for use with AmigaOS by Olaf Barthel <obarthel -at- gmx -dot- net>
16 #include "smbfs.h"
17 #if !defined(__AROS__)
18 #include "quad_math.h"
19 #endif
21 /*****************************************************************************/
23 #include <smb/smb.h>
24 #include <smb/smbno.h>
25 #include <smb/smb_fs.h>
27 /*****************************************************************************/
29 #define SMB_VWV(packet) ((packet) + SMB_HEADER_LEN)
30 #define SMB_CMD(packet) ((packet)[8])
31 #define SMB_WCT(packet) ((packet)[SMB_HEADER_LEN - 1])
32 #define SMB_BCC(packet) smb_bcc(packet)
33 #define SMB_BUF(packet) ((packet) + SMB_HEADER_LEN + SMB_WCT(packet) * 2 + 2)
35 #define SMB_DIRINFO_SIZE 43
36 #define SMB_STATUS_SIZE 21
38 /*****************************************************************************/
40 static INLINE byte * smb_encode_word(byte *p, word data);
41 static INLINE byte * smb_decode_word(byte *p, word *data);
42 static INLINE word smb_bcc(const byte *packet);
43 static INLINE int smb_verify(const byte *packet, int command, int wct, int bcc);
44 static byte *smb_encode_dialect(byte *p, const byte *name, int len);
45 static byte *smb_encode_ascii(byte *p, const byte *name, int len);
46 static void smb_encode_vblock(byte *p, const byte *data, word len, int unused_fs);
47 static byte *smb_decode_data(const byte *p, byte *data, word *data_len, int fs);
48 static byte *smb_name_mangle(byte *p, const byte *name);
49 static int date_dos2unix(unsigned short time_value, unsigned short date);
50 static void date_unix2dos(int unix_date, unsigned short *time_value, unsigned short *date);
51 static INLINE int smb_valid_packet(const byte *packet);
52 static int smb_errno(int errcls, int error);
53 static int smb_request_ok(struct smb_server *s, int command, int wct, int bcc);
54 static int smb_retry(struct smb_server *server);
55 static int smb_request_ok_unlock(struct smb_server *s, int command, int wct, int bcc);
56 static byte *smb_setup_header(struct smb_server *server, byte command, word wct, word bcc);
57 static byte *smb_setup_header_exclusive(struct smb_server *server, byte command, word wct, word bcc);
58 static int smb_proc_do_create(struct smb_server *server, const char *path, int len, struct smb_dirent *entry, word command);
59 static char *smb_decode_dirent(char *p, struct smb_dirent *entry);
60 static int smb_proc_readdir_short(struct smb_server *server, char *path, int fpos, int cache_size, struct smb_dirent *entry);
61 static char *smb_decode_long_dirent(char *p, struct smb_dirent *finfo, int level);
62 static int smb_proc_readdir_long(struct smb_server *server, char *path, int fpos, int cache_size, struct smb_dirent *entry);
63 static int smb_proc_reconnect(struct smb_server *server);
64 static void smb_printerr(int class, int num);
66 /*****************************************************************************/
68 /*****************************************************************************
70 * Encoding/Decoding section
72 *****************************************************************************/
73 static INLINE byte *
74 smb_encode_word (byte * p, word data)
76 p[0] = data & 0x00ffU;
77 p[1] = (data & 0xff00U) >> 8;
78 return &p[2];
81 static INLINE byte *
82 smb_decode_word (byte * p, word * data)
84 (*data) = (word) (p[0] | ((word)p[1]) << 8);
85 return &(p[2]);
88 byte *
89 smb_encode_smb_length (byte * p, dword len)
91 /* 0x00 = NetBIOS session message */
92 p[0] = 0;
94 /* 0 = reserved */
95 p[1] = 0;
97 /* Payload length in network byte order. */
98 p[2] = (len & 0xFF00) >> 8;
99 p[3] = (len & 0xFF);
101 /* Length is actually a 17 bit integer. */
102 p[1] |= (len >> 16) & 1;
104 return &p[4];
107 static byte *
108 smb_encode_dialect (byte * p, const byte * name, int len)
110 (*p++) = 2;
111 strcpy (p, name);
113 return p + len + 1;
116 static byte *
117 smb_encode_ascii (byte * p, const byte * name, int len)
119 (*p++) = 4;
120 strcpy (p, name);
122 return p + len + 1;
125 static void
126 smb_encode_vblock (byte * p, const byte * data, word len, int unused_fs)
128 (*p++) = 5;
129 p = smb_encode_word (p, len);
130 memcpy (p, data, len);
133 static byte *
134 smb_decode_data (const byte * p, byte * data, word * data_len, int unused_fs)
136 word len;
138 if (!((*p) == 1 || (*p) == 5))
139 LOG (("Warning! Data block not starting with 1 or 5\n"));
141 len = WVAL (p, 1);
142 p += 3;
144 memcpy (data, p, len);
146 (*data_len) = len;
148 return (byte *)p + len;
151 static byte *
152 smb_name_mangle (byte * p, const byte * name)
154 int len, pad = 0;
156 len = strlen (name);
158 if (len < 16)
159 pad = 16 - len;
161 (*p++) = 2 * (len + pad);
163 while ((*name) != '\0')
165 (*p++) = ((*name) >> 4) + 'A';
166 (*p++) = ((*name) & 0x0F) + 'A';
168 name++;
171 while (pad-- > 0)
173 (*p++) = 'C';
174 (*p++) = 'A';
177 (*p++) = '\0';
179 return p;
182 /* According to the core protocol documentation times are
183 expressed as seconds past January 1st, 1970, local
184 time zone. */
185 static INLINE int
186 utc2local (int time_value)
188 int result;
190 if(time_value > 0)
191 result = time_value - GetTimeZoneDelta();
192 else
193 result = time_value;
195 return result;
198 static INLINE int
199 local2utc (int time_value)
201 int result;
203 if(time_value > 0)
204 result = time_value + GetTimeZoneDelta();
205 else
206 result = time_value;
208 return result;
211 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since January 1st 1970). */
212 static int
213 date_dos2unix (unsigned short time_value, unsigned short date)
215 time_t seconds;
216 struct tm tm;
218 memset(&tm,0,sizeof(tm));
220 tm.tm_sec = 2 * (time_value & 0x1F);
221 tm.tm_min = (time_value >> 5) & 0x3F;
222 tm.tm_hour = (time_value >> 11) & 0x1F;
223 tm.tm_mday = date & 0x1F;
224 tm.tm_mon = ((date >> 5) & 0xF) - 1;
225 tm.tm_year = ((date >> 9) & 0x7F) + 80;
227 seconds = MakeTime(&tm);
229 return(seconds);
232 /* Convert linear UNIX date to a MS-DOS time/date pair. */
233 static void
234 date_unix2dos (int unix_date, unsigned short *time_value, unsigned short *date)
236 struct tm tm;
238 GMTime(unix_date,&tm);
240 (*time_value) = (tm.tm_hour << 11) | (tm.tm_min << 5) | (tm.tm_sec / 2);
241 (*date) = ((tm.tm_year - 80) << 9) | ((tm.tm_mon + 1) << 5) | tm.tm_mday;
244 /****************************************************************************
246 * Support section.
248 ****************************************************************************/
249 dword
250 smb_len (const byte * packet)
252 /* This returns the payload length stored in the NetBIOS session header. */
253 return (dword)( (((dword)(packet[1] & 0x1)) << 16) | (((dword)packet[2]) << 8) | (packet[3]) );
256 static INLINE word
257 smb_bcc (const byte * packet)
259 int pos = SMB_HEADER_LEN + SMB_WCT (packet) * sizeof (word);
261 return (word)(packet[pos] | ((word)packet[pos + 1]) << 8);
264 /* smb_valid_packet: We check if packet fulfills the basic
265 requirements of a smb packet */
266 static INLINE int
267 smb_valid_packet (const byte * packet)
269 int result;
271 LOG (("len: %ld, wct: %ld, bcc: %ld -- SMB_HEADER_LEN[%ld] + SMB_WCT (packet) * 2[%ld] + SMB_BCC (packet)[%ld] + 2 = %ld\n",
272 smb_len (packet),
273 SMB_WCT (packet),
274 SMB_BCC (packet),
275 SMB_HEADER_LEN,
276 SMB_WCT (packet) * 2,
277 SMB_BCC (packet),
278 SMB_HEADER_LEN + SMB_WCT (packet) * 2 + SMB_BCC (packet) + 2));
280 /* olsen: During protocol negotiation Samba 3.2.5 may return SMB responses which contain
281 more data than is called for. I'm not sure what the right approach to handle
282 this would be. But for now, I've modified this test to check only if there
283 is less data in a response than required. */
284 result = (packet[4] == 0xff
285 && packet[5] == 'S'
286 && packet[6] == 'M'
287 && packet[7] == 'B'
288 && (smb_len (packet) + 4 >= (dword)
289 (SMB_HEADER_LEN + SMB_WCT (packet) * 2 + SMB_BCC (packet) + 2))) ? 0 : (-EIO);
291 return result;
294 /* smb_verify: We check if we got the answer we expected, and if we
295 got enough data. If bcc == -1, we don't care. */
296 static INLINE int
297 smb_verify (const byte * packet, int command, int wct, int bcc)
299 return (SMB_CMD (packet) == command &&
300 SMB_WCT (packet) >= wct &&
301 (bcc == -1 || SMB_BCC (packet) >= bcc)) ? 0 : -EIO;
304 static int
305 smb_errno (int errcls, int error)
307 int result,i;
309 if (errcls)
310 smb_printerr (errcls, error);
312 if (errcls == ERRDOS)
314 static const int map[][2] =
316 { ERRbadfunc,EINVAL },
317 { ERRbadfile,ENOENT },
318 { ERRbadpath,ENOENT },
319 { ERRnofids,EMFILE },
320 { ERRnoaccess,EACCES },
321 { ERRbadfid,EBADF },
322 { ERRbadmcb,EIO },
323 { ERRnomem,ENOMEM },
324 { ERRbadmem,EFAULT },
325 { ERRbadenv,EIO },
326 { ERRbadformat,EIO },
327 { ERRbadaccess,EACCES },
328 { ERRbaddata,E2BIG },
329 { ERRbaddrive,ENXIO },
330 { ERRremcd,EIO },
331 { ERRdiffdevice,EXDEV },
332 { ERRnofiles,0 },
333 { ERRbadshare,ETXTBSY },
334 { ERRlock,EDEADLK },
335 { ERRfilexists,EEXIST },
336 { 87,0 },/* Unknown error! */
337 { 183,EEXIST },/* This next error seems to occur on an mv when the destination exists */
338 { -1,-1 }
341 result = EIO;
343 for(i = 0 ; map[i][0] != -1 ; i++)
345 if(map[i][0] == error)
347 result = map[i][1];
348 break;
352 else if (errcls == ERRSRV)
354 static const int map[][2] =
356 { ERRerror,ENFILE },
357 { ERRbadpw,EINVAL },
358 { ERRbadtype,EIO },
359 { ERRaccess,EACCES },
360 { -1, -1 }
363 result = EIO;
365 for(i = 0 ; map[i][0] != -1 ; i++)
367 if(map[i][0] == error)
369 result = map[i][1];
370 break;
374 else if (errcls == ERRHRD)
376 static const int map[][2] =
378 { ERRnowrite,EROFS },
379 { ERRbadunit,ENODEV },
380 { ERRnotready,EBUSY },
381 { ERRbadcmd,EIO },
382 { ERRdata,EIO },
383 { ERRbadreq,ERANGE },
384 { ERRbadshare,ETXTBSY },
385 { ERRlock,EDEADLK },
386 { -1, -1 }
389 result = EIO;
391 for(i = 0 ; map[i][0] != -1 ; i++)
393 if(map[i][0] == error)
395 result = map[i][1];
396 break;
400 else if (errcls == ERRCMD)
402 result = EIO;
404 else
406 result = 0;
409 return(result);
412 #if DEBUG
414 static char
415 print_char (char c)
417 if ((c < ' ') || (c > '~'))
418 return '.';
420 return c;
423 static void
424 smb_dump_packet (byte * packet)
426 int i, j, len;
427 int errcls, error;
429 errcls = (int) packet[9];
430 error = (int) (int) (packet[11] | ((int)packet[12]) << 8);
432 LOG (("smb_len = %ld valid = %ld\n", len = smb_len (packet), smb_valid_packet (packet)));
433 LOG (("smb_cmd = %ld smb_wct = %ld smb_bcc = %ld\n", packet[8], SMB_WCT (packet), SMB_BCC (packet)));
434 LOG (("smb_rcls = %ld smb_err = %ld\n", errcls, error));
436 if (errcls)
437 smb_printerr (errcls, error);
439 if (len > 100)
440 len = 100;
442 PRINTHEADER();
444 for (i = 0; i < len; i += 10)
446 PRINTF (("%03ld:", i));
448 for (j = i; j < i + 10; j++)
450 if (j < len)
451 PRINTF (("%02lx ", packet[j]));
452 else
453 PRINTF ((" "));
456 PRINTF ((": "));
458 for (j = i; j < i + 10; j++)
460 if (j < len)
461 PRINTF (("%lc", print_char (packet[j])));
464 PRINTF (("\n"));
468 #endif /* DEBUG */
470 /* smb_request_ok: We expect the server to be locked. Then we do the
471 request and check the answer completely. When smb_request_ok
472 returns 0, you can be quite sure that everything went well. When
473 the answer is <=0, the returned number is a valid unix errno. */
474 static int
475 smb_request_ok (struct smb_server *s, int command, int wct, int bcc)
477 int result;
478 int error;
480 s->rcls = 0;
481 s->err = 0;
483 result = smb_request (s);
484 if (result < 0)
486 LOG (("smb_request failed\n"));
488 else if ((error = smb_valid_packet (s->packet)) != 0)
490 LOG (("not a valid packet!\n"));
491 result = error;
493 else if (s->rcls != 0)
495 result = -smb_errno (s->rcls, s->err);
497 else if ((error = smb_verify (s->packet, command, wct, bcc)) != 0)
499 LOG (("smb_verify failed\n"));
500 result = error;
503 return(result);
506 /* smb_retry: This function should be called when smb_request_ok has
507 indicated an error. If the error was indicated because the
508 connection was killed, we try to reconnect. If smb_retry returns 0,
509 the error was indicated for another reason, so a retry would not be
510 of any use. */
511 static int
512 smb_retry (struct smb_server *server)
514 int result = 0;
516 if (server->state == CONN_VALID)
517 goto out;
519 if (smb_release (server) < 0)
521 LOG (("smb_retry: smb_release failed\n"));
522 server->state = CONN_RETRIED;
523 goto out;
526 if (smb_proc_reconnect (server) < 0)
528 LOG (("smb_proc_reconnect failed\n"));
529 server->state = CONN_RETRIED;
530 goto out;
533 server->state = CONN_VALID;
534 result = 1;
536 out:
538 return result;
541 static int
542 smb_request_ok_unlock (struct smb_server *s, int command, int wct, int bcc)
544 int result;
546 result = smb_request_ok (s, command, wct, bcc);
548 return result;
551 /* smb_setup_header: We completely set up the packet. You only have to
552 insert the command-specific fields */
553 static byte *
554 smb_setup_header (struct smb_server *server, byte command, word wct, word bcc)
556 dword xmit_len = SMB_HEADER_LEN + wct * sizeof (word) + bcc + 2;
557 byte *p = server->packet;
558 byte *buf = server->packet;
560 /* This sets up the NetBIOS session header. 'xmit_length'
561 * is the amount of data that follows the header.
563 p = smb_encode_smb_length (p, xmit_len);
565 BSET (p, 0, 0xff);
566 BSET (p, 1, 'S');
567 BSET (p, 2, 'M');
568 BSET (p, 3, 'B');
569 BSET (p, 4, command);
571 /* Fixed header length (32 bytes). */
572 memset (&p[5], 0, 32 - 5);
574 p += 32;
576 WSET (buf, smb_tid, server->tid);
577 WSET (buf, smb_pid, 0); /* server->pid */
578 WSET (buf, smb_uid, server->server_uid);
579 WSET (buf, smb_mid, 0); /* server->mid */
581 if (server->protocol > PROTOCOL_CORE)
583 BSET (buf, smb_flg, 0x8); /* path names are caseless */
584 WSET (buf, smb_flg2, 0x3); /* extended attributes supported, long names supported */
587 (*p++) = wct;
588 p += 2 * wct;
589 WSET (p, 0, bcc);
591 return p + 2;
594 /* smb_setup_header_exclusive waits on server->lock and locks the
595 server, when it's free. You have to unlock it manually when you're
596 finished with server->packet! */
597 static byte *
598 smb_setup_header_exclusive (struct smb_server *server, byte command, word wct, word bcc)
600 byte * result;
602 result = smb_setup_header (server, command, wct, bcc);
604 return result;
607 /*****************************************************************************
609 * File operation section.
611 ****************************************************************************/
614 smb_proc_open (struct smb_server *server, const char *pathname, int len, struct smb_dirent *entry)
616 int error;
617 char *p;
618 char *buf = server->packet;
619 const word o_attr = aSYSTEM | aHIDDEN | aDIR;
621 LOG (("path=%s\n", pathname));
623 retry:
625 p = smb_setup_header (server, SMBopen, 2, 2 + len);
626 WSET (buf, smb_vwv0, 0x42); /* read/write */
627 WSET (buf, smb_vwv1, o_attr);
628 smb_encode_ascii (p, pathname, len);
630 if ((error = smb_request_ok (server, SMBopen, 7, 0)) < 0)
632 if (smb_retry (server))
633 goto retry;
635 if (error != -EACCES)
636 goto out;
638 p = smb_setup_header (server, SMBopen, 2, 2 + len);
639 WSET (buf, smb_vwv0, 0x40); /* read only */
640 WSET (buf, smb_vwv1, o_attr);
641 smb_encode_ascii (p, pathname, len);
643 if ((error = smb_request_ok (server, SMBopen, 7, 0)) < 0)
645 if (smb_retry (server))
646 goto retry;
648 goto out;
652 /* We should now have data in vwv[0..6]. */
653 entry->fileid = WVAL (buf, smb_vwv0);
654 entry->attr = WVAL (buf, smb_vwv1);
655 entry->ctime = entry->atime = entry->mtime = entry->wtime = local2utc (DVAL (buf, smb_vwv2));
656 entry->size = DVAL (buf, smb_vwv4);
657 entry->opened = 1;
659 #if DEBUG
661 struct tm tm;
663 GMTime(entry->ctime,&tm);
664 LOG(("ctime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
666 GMTime(entry->atime,&tm);
667 LOG(("atime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
669 GMTime(entry->mtime,&tm);
670 LOG(("mtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
672 GMTime(entry->wtime,&tm);
673 LOG(("wtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
675 #endif /* DEBUG */
677 out:
679 return error;
682 /* smb_proc_close: in finfo->mtime we can send a modification time to
683 the server */
685 smb_proc_close (struct smb_server *server, word fileid, dword mtime)
687 char *buf = server->packet;
688 int local_time;
689 int result;
691 if(mtime != 0 && mtime != 0xffffffff)
693 /* 0 and 0xffffffff mean: do not set mtime */
694 local_time = utc2local (mtime);
696 else
698 local_time = mtime;
701 smb_setup_header_exclusive (server, SMBclose, 3, 0);
702 WSET (buf, smb_vwv0, fileid);
703 DSET (buf, smb_vwv1, local_time);
705 result = smb_request_ok_unlock (server, SMBclose, 0, 0);
707 return result;
710 /* In smb_proc_read and smb_proc_write we do not retry, because the
711 file-id would not be valid after a reconnection. */
713 /* smb_proc_read: fs indicates if it should be copied with
714 memcpy_tofs. */
716 smb_proc_read (struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, char *data, int fs)
718 word returned_count, data_len;
719 char *buf = server->packet;
720 int result;
721 int error;
723 smb_setup_header_exclusive (server, SMBread, 5, 0);
725 WSET (buf, smb_vwv0, finfo->fileid);
726 WSET (buf, smb_vwv1, count);
727 DSET (buf, smb_vwv2, offset);
728 WSET (buf, smb_vwv4, 0);
730 if ((error = smb_request_ok (server, SMBread, 5, -1)) < 0)
732 result = error;
733 goto out;
736 returned_count = WVAL (buf, smb_vwv0);
738 smb_decode_data (SMB_BUF (server->packet), data, &data_len, fs);
740 if (returned_count != data_len)
742 LOG (("Warning, returned_count != data_len\n"));
743 LOG (("ret_c=%ld, data_len=%ld\n", returned_count, data_len));
745 else
747 LOG (("ret_c=%ld, data_len=%ld\n", returned_count, data_len));
750 result = data_len;
752 out:
754 return result;
757 /* count must be <= 65535. No error number is returned. A result of 0
758 indicates an error, which has to be investigated by a normal read
759 call. */
761 smb_proc_read_raw (struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, char *data)
763 char *buf = server->packet;
764 int result;
766 smb_setup_header_exclusive (server, SMBreadbraw, 8, 0);
768 WSET (buf, smb_vwv0, finfo->fileid);
769 DSET (buf, smb_vwv1, offset);
770 WSET (buf, smb_vwv3, count); /* maxcnt */
771 WSET (buf, smb_vwv4, 0); /* mincnt */
772 DSET (buf, smb_vwv5, 0); /* timeout */
773 WSET (buf, smb_vwv7, 0); /* reserved */
775 result = smb_request_read_raw (server, data, count);
777 return result;
781 smb_proc_write (struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, const char *data)
783 int res;
784 char *buf = server->packet;
785 byte *p;
787 p = smb_setup_header_exclusive (server, SMBwrite, 5, count + 3);
788 WSET (buf, smb_vwv0, finfo->fileid);
789 WSET (buf, smb_vwv1, count);
790 DSET (buf, smb_vwv2, offset);
791 WSET (buf, smb_vwv4, 0);
793 (*p++) = 1;
794 WSET (p, 0, count);
795 memcpy (p + 2, data, count);
797 if ((res = smb_request_ok (server, SMBwrite, 1, 0)) >= 0)
798 res = WVAL (buf, smb_vwv0);
800 return res;
803 /* count must be <= 65535 */
805 smb_proc_write_raw (struct smb_server *server, struct smb_dirent *finfo, off_t offset, long count, const char *data)
807 char *buf = server->packet;
808 int result;
809 long len = server->max_buffer_size - 4;
810 byte *p;
812 if (len >= count)
813 len = 0;
814 else
815 len = count - len; /* transfer the larger part using the second packet */
817 p = smb_setup_header_exclusive (server, SMBwritebraw, server->protocol > PROTOCOL_COREPLUS ? 12 : 11, len);
819 WSET (buf, smb_vwv0, finfo->fileid);
820 DSET (buf, smb_vwv1, count);
821 DSET (buf, smb_vwv3, offset);
822 DSET (buf, smb_vwv5, 0); /* timeout */
823 WSET (buf, smb_vwv7, 1); /* send final result response */
824 DSET (buf, smb_vwv8, 0); /* reserved */
826 if (server->protocol > PROTOCOL_COREPLUS)
828 WSET (buf, smb_vwv10, len);
829 WSET (buf, smb_vwv11, p - smb_base(buf));
831 else
833 WSET (buf, smb_vwv10, 0);
836 if (len > 0)
837 memcpy (p, data, len);
839 result = smb_request_ok (server, SMBwritebraw, 1, 0);
841 LOG (("first request returned %ld\n", result));
843 if (result < 0)
844 goto out;
846 result = smb_request_write_raw (server, data + len, count - len);
848 LOG(("raw request returned %ld\n", result));
850 if (result > 0)
852 int error;
854 /* We have to do the checks of smb_request_ok here as well */
855 if ((error = smb_valid_packet (server->packet)) != 0)
857 LOG (("not a valid packet!\n"));
858 result = error;
860 else if (server->rcls != 0)
862 result = -smb_errno (server->rcls, server->err);
864 else
866 int sock_fd = server->mount_data.fd;
868 /* SMBwritebraw may be followed by the server sending
869 * several interim update responses of SMBwritebraw,
870 * which are eventually followed by a final response
871 * of SMBwritec (complete).
873 while(SMB_CMD(server->packet) == SMBwritebraw && SMB_BCC(server->packet) == 0 && SMB_WCT(server->packet) == 1)
875 error = smb_receive (server, sock_fd);
876 if(error < 0)
878 result = error;
879 break;
882 error = smb_valid_packet (server->packet);
883 if(error != 0)
885 result = error;
886 break;
889 if (server->rcls != 0)
891 result = -smb_errno (server->rcls, server->err);
892 break;
896 /* If everything went fine so far, this should be the
897 * final packet which concludes the transfer.
899 if(result >= 0)
901 error = smb_verify (server->packet, SMBwritec, 1, 0);
902 if (error != 0)
904 LOG (("smb_verify failed\n"));
905 result = error;
910 /* If everything went fine, the whole block has been transfered. */
911 if (result == (count - len))
912 result = count;
915 out:
917 return result;
921 smb_proc_lseek (struct smb_server *server, struct smb_dirent *finfo, off_t offset, int mode, off_t * new_position_ptr)
923 char *buf = server->packet;
924 int error;
926 retry:
928 smb_setup_header (server, SMBlseek, 4,0);
930 WSET (buf, smb_vwv0, finfo->fileid);
931 WSET (buf, smb_vwv1, mode);
932 DSET (buf, smb_vwv2, offset);
934 if ((error = smb_request_ok (server, SMBlseek, 1, 0)) < 0)
936 if (smb_retry (server))
937 goto retry;
939 else
941 (*new_position_ptr) = DVAL(buf, smb_vwv0);
944 return error;
947 /* smb_proc_lockingX: We don't chain any further packets to the initial one */
949 smb_proc_lockingX (struct smb_server *server, struct smb_dirent *finfo, struct smb_lkrng *locks, int num_entries, int mode, long timeout)
951 int result;
952 int num_locks, num_unlocks;
953 char *buf = server->packet;
954 char *data;
955 struct smb_lkrng *p;
956 int i;
958 num_locks = num_unlocks = 0;
960 if (mode & 2)
961 num_unlocks = num_entries;
962 else
963 num_locks = num_entries;
965 retry:
967 data = smb_setup_header(server, SMBlockingX, 8, num_entries * 10);
969 BSET (buf, smb_vwv0, 0xFF);
970 WSET (buf, smb_vwv1, 0);
971 WSET (buf, smb_vwv2, finfo->fileid);
972 WSET (buf, smb_vwv3, mode & 1); /* must be WSET() or new oplock level will be random */
973 DSET (buf, smb_vwv4, timeout);
974 WSET (buf, smb_vwv6, num_unlocks);
975 WSET (buf, smb_vwv7, num_locks);
977 for (i = 0, p = locks; i < num_entries; i++, p++)
979 WSET (data, SMB_LPID_OFFSET(i), 0); /* server->pid */
980 DSET (data, SMB_LKOFF_OFFSET(i), p->offset);
981 DSET (data, SMB_LKLEN_OFFSET(i), p->len);
984 if ((result = smb_request_ok (server, SMBlockingX, 0, 0)) < 0)
986 if (smb_retry (server))
987 goto retry;
990 return result;
993 /* smb_proc_do_create: We expect entry->attry & entry->ctime to be set. */
994 static int
995 smb_proc_do_create (struct smb_server *server, const char *path, int len, struct smb_dirent *entry, word command)
997 int error;
998 char *p;
999 char *buf = server->packet;
1000 int local_time;
1002 retry:
1004 p = smb_setup_header (server, command, 3, len + 2);
1005 WSET (buf, smb_vwv0, entry->attr);
1006 local_time = utc2local (entry->ctime);
1007 DSET (buf, smb_vwv1, local_time);
1008 smb_encode_ascii (p, path, len);
1010 if ((error = smb_request_ok (server, command, 1, 0)) < 0)
1012 if (smb_retry (server))
1013 goto retry;
1015 goto out;
1018 entry->opened = 1;
1019 entry->fileid = WVAL (buf, smb_vwv0);
1021 smb_proc_close (server, entry->fileid, entry->mtime);
1023 out:
1025 return error;
1029 smb_proc_create (struct smb_server *server, const char *path, int len, struct smb_dirent *entry)
1031 return smb_proc_do_create (server, path, len, entry, SMBcreate);
1035 smb_proc_mv (struct smb_server *server, const char *opath, const int olen, const char *npath, const int nlen)
1037 char *p;
1038 char *buf = server->packet;
1039 int result;
1041 retry:
1043 p = smb_setup_header (server, SMBmv, 1, olen + nlen + 4);
1045 WSET (buf, smb_vwv0, 0);
1047 p = smb_encode_ascii (p, opath, olen);
1048 smb_encode_ascii (p, npath, olen);
1050 if ((result = smb_request_ok (server, SMBmv, 0, 0)) < 0)
1052 if (smb_retry (server))
1053 goto retry;
1056 return result;
1060 smb_proc_mkdir (struct smb_server *server, const char *path, const int len)
1062 char *p;
1063 int result;
1065 retry:
1067 p = smb_setup_header (server, SMBmkdir, 0, 2 + len);
1069 smb_encode_ascii (p, path, len);
1071 if ((result = smb_request_ok (server, SMBmkdir, 0, 0)) < 0)
1073 if (smb_retry (server))
1074 goto retry;
1077 return result;
1081 smb_proc_rmdir (struct smb_server *server, const char *path, const int len)
1083 char *p;
1084 int result;
1086 retry:
1088 p = smb_setup_header (server, SMBrmdir, 0, 2 + len);
1090 smb_encode_ascii (p, path, len);
1092 if ((result = smb_request_ok (server, SMBrmdir, 0, 0)) < 0)
1094 if (smb_retry (server))
1095 goto retry;
1098 return result;
1102 smb_proc_unlink (struct smb_server *server, const char *path, const int len)
1104 char *p;
1105 char *buf = server->packet;
1106 int result;
1108 retry:
1110 p = smb_setup_header (server, SMBunlink, 1, 2 + len);
1112 WSET (buf, smb_vwv0, 0);
1114 smb_encode_ascii (p, path, len);
1116 if ((result = smb_request_ok (server, SMBunlink, 0, 0)) < 0)
1118 if (smb_retry (server))
1119 goto retry;
1122 return result;
1126 smb_proc_trunc (struct smb_server *server, word fid, dword length)
1128 char *p;
1129 char *buf = server->packet;
1130 int result;
1132 p = smb_setup_header (server, SMBwrite, 5, 3);
1133 WSET (buf, smb_vwv0, fid);
1134 WSET (buf, smb_vwv1, 0);
1135 DSET (buf, smb_vwv2, length);
1136 WSET (buf, smb_vwv4, 0);
1137 smb_encode_ascii (p, "", 0);
1139 result = smb_request_ok (server, SMBwrite, 1, 0);
1140 if (result >= 0)
1141 result = DVAL(buf, smb_vwv0);
1143 return result;
1146 static char *
1147 smb_decode_dirent (char *p, struct smb_dirent *entry)
1149 size_t name_size;
1151 p += SMB_STATUS_SIZE; /* reserved (search_status) */
1153 entry->attr = BVAL (p, 0);
1154 entry->mtime = entry->atime = entry->ctime = entry->wtime = date_dos2unix (WVAL (p, 1), WVAL (p, 3));
1155 entry->size = DVAL (p, 5);
1157 name_size = 13;
1159 if(name_size > entry->complete_path_size-1)
1160 name_size = entry->complete_path_size-1;
1162 memcpy (entry->complete_path, p + 9, name_size);
1164 entry->complete_path[name_size] = '\0';
1166 LOG (("smb_decode_dirent: path = %s\n", entry->complete_path));
1168 #if DEBUG
1170 struct tm tm;
1172 GMTime(entry->ctime,&tm);
1173 LOG(("ctime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
1175 GMTime(entry->atime,&tm);
1176 LOG(("atime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
1178 GMTime(entry->mtime,&tm);
1179 LOG(("mtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
1181 GMTime(entry->wtime,&tm);
1182 LOG(("wtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
1184 #endif /* DEBUG */
1186 return p + 22;
1189 /* This routine is used to read in directory entries from the network.
1190 Note that it is for short directory name seeks, i.e.: protocol < PROTOCOL_LANMAN2 */
1191 static int
1192 smb_proc_readdir_short (struct smb_server *server, char *path, int fpos, int cache_size, struct smb_dirent *entry)
1194 char *p;
1195 char *buf;
1196 int error;
1197 int result = 0;
1198 int i;
1199 int first, total_count;
1200 struct smb_dirent *current_entry;
1201 word bcc;
1202 word count;
1203 char status[SMB_STATUS_SIZE];
1204 int entries_asked = (server->max_buffer_size - 100) / SMB_DIRINFO_SIZE;
1205 int dirlen = strlen (path);
1206 char * mask;
1208 mask = malloc(dirlen + 4 + 1);
1209 if (mask == NULL)
1211 result = (-ENOMEM);
1212 goto out;
1215 strcpy (mask, path);
1216 strcat (mask, "\\*.*");
1218 LOG (("SMB call readdir %ld @ %ld\n", cache_size, fpos));
1219 LOG ((" mask = %s\n", mask));
1221 buf = server->packet;
1223 retry:
1225 first = 1;
1226 total_count = 0;
1227 current_entry = entry;
1229 while (1)
1231 if (first == 1)
1233 p = smb_setup_header (server, SMBsearch, 2, 5 + strlen (mask));
1234 WSET (buf, smb_vwv0, entries_asked);
1235 WSET (buf, smb_vwv1, aDIR);
1236 p = smb_encode_ascii (p, mask, strlen (mask));
1237 (*p++) = 5;
1238 (void) smb_encode_word (p, 0);
1240 else
1242 p = smb_setup_header (server, SMBsearch, 2, 5 + SMB_STATUS_SIZE);
1243 WSET (buf, smb_vwv0, entries_asked);
1244 WSET (buf, smb_vwv1, aDIR);
1245 p = smb_encode_ascii (p, "", 0);
1246 (void) smb_encode_vblock (p, status, SMB_STATUS_SIZE, 0);
1249 if ((error = smb_request_ok (server, SMBsearch, 1, -1)) < 0)
1251 if ((server->rcls == ERRDOS) && (server->err == ERRnofiles))
1253 result = total_count - fpos;
1254 goto unlock_return;
1256 else
1258 if (smb_retry (server))
1259 goto retry;
1261 result = error;
1263 goto unlock_return;
1267 p = SMB_VWV (server->packet);
1268 p = smb_decode_word (p, &count); /* vwv[0] = count-returned */
1269 p = smb_decode_word (p, &bcc);
1271 first = 0;
1273 if (count <= 0)
1275 result = total_count - fpos;
1277 goto unlock_return;
1280 if (bcc != count * SMB_DIRINFO_SIZE + 3)
1282 result = -EIO;
1284 goto unlock_return;
1287 p += 3; /* Skipping VBLOCK header (5, length lo, length hi). */
1289 /* Read the last entry into the status field. */
1290 memcpy (status, SMB_BUF (server->packet) + 3 + (count - 1) * SMB_DIRINFO_SIZE, SMB_STATUS_SIZE);
1292 /* Now we are ready to parse smb directory entries. */
1294 for (i = 0; i < count; i++)
1296 if (total_count < fpos)
1298 p += SMB_DIRINFO_SIZE;
1300 LOG (("smb_proc_readdir: skipped entry; total_count = %ld, i = %ld, fpos = %ld\n", total_count, i, fpos));
1302 else if (total_count >= fpos + cache_size)
1304 result = total_count - fpos;
1306 goto unlock_return;
1308 else
1310 p = smb_decode_dirent (p, current_entry);
1312 current_entry += 1;
1315 total_count += 1;
1319 unlock_return:
1321 if(mask != NULL)
1322 free(mask);
1324 out:
1326 return result;
1329 /*****************************************************************************/
1331 #if !defined(__AROS__)
1332 /* Interpret an 8 byte "filetime" structure to a 'time_t'.
1333 * It's originally in "100ns units since jan 1st 1601".
1335 * Unlike the Samba implementation of that date conversion
1336 * algorithm this one tries to perform the entire
1337 * calculation using integer operations only.
1339 static time_t
1340 interpret_long_date(char * p)
1342 QUAD adjust;
1343 QUAD long_date;
1344 ULONG underflow;
1345 time_t result;
1347 /* Extract the 64 bit time value. */
1348 long_date.Low = DVAL(p,0);
1349 long_date.High = DVAL(p,4);
1351 /* Divide by 10,000,000 to convert the time from 100ns
1352 units into seconds. */
1353 divide_64_by_32(&long_date,10000000,&long_date);
1355 /* Adjust by 369 years (11,644,473,600 seconds) to convert
1356 from the epoch beginning on January 1st 1601 to the one
1357 beginning on January 1st 1970 (the Unix epoch). */
1358 adjust.Low = 0xb6109100;
1359 adjust.High = 0x00000002;
1361 underflow = subtract_64_from_64_to_64(&long_date,&adjust,&long_date);
1363 /* If the result did not produce an underflow or overflow,
1364 return the number of seconds encoded in the least
1365 significant word of the result. */
1366 if(underflow == 0 && long_date.High == 0)
1367 result = long_date.Low;
1368 else
1369 result = 0;
1371 return(result);
1373 #else
1374 static time_t
1375 interpret_long_date(char * p)
1377 UQUAD long_date;
1378 int sectime;
1380 long_date = *(UQUAD *)p - (0x2B6109100ULL * 10000000);
1381 sectime = long_date / 10000000;
1383 return((time_t)sectime);
1385 #endif
1387 /*****************************************************************************/
1389 static void
1390 smb_get_dirent_name(char *p,int level,char ** name_ptr,int * len_ptr)
1392 switch (level)
1394 case 1: /* OS/2 understands this */
1395 (*name_ptr) = p + 27;
1396 (*len_ptr) = strlen(p + 27);
1397 break;
1399 case 2: /* this is what OS/2 uses */
1400 (*name_ptr) = p + 31;
1401 (*len_ptr) = strlen(p + 31);
1402 break;
1404 case 3: /* untested */
1405 (*name_ptr) = p + 33;
1406 (*len_ptr) = strlen(p + 33);
1407 break;
1409 case 4: /* untested */
1410 (*name_ptr) = p + 37;
1411 (*len_ptr) = strlen(p + 37);
1412 break;
1414 case 260: /* NT uses this, but also accepts 2 */
1415 (*name_ptr) = p + 94;
1416 (*len_ptr) = min (DVAL (p+60, 0), SMB_MAXNAMELEN);
1417 break;
1419 default:
1420 (*name_ptr) = NULL;
1421 (*len_ptr) = 0;
1422 break;
1426 /* interpret a long filename structure - this is mostly guesses at the
1427 moment. The length of the structure is returned. The structure of
1428 a long filename depends on the info level. 260 is used by NT and 2
1429 is used by OS/2. */
1430 static char *
1431 smb_decode_long_dirent (char *p, struct smb_dirent *finfo, int level)
1433 char *result;
1435 switch (level)
1437 case 1: /* OS/2 understands this */
1439 #if DEBUG
1441 char buffer[255];
1443 memcpy(buffer,p + 27,sizeof(buffer)-1);
1444 buffer[sizeof(buffer)-1] = '\0';
1446 LOG(("type=%ld, name='%s'\n",level,buffer));
1448 #endif /* DEBUG */
1450 if (finfo != NULL)
1452 strlcpy (finfo->complete_path, p + 27, finfo->complete_path_size);
1453 finfo->len = strlen (finfo->complete_path);
1454 finfo->size = DVAL (p, 16);
1455 finfo->attr = BVAL (p, 24);
1456 finfo->ctime = date_dos2unix (WVAL (p, 6), WVAL (p, 4));
1457 finfo->atime = date_dos2unix (WVAL (p, 10), WVAL (p, 8));
1458 finfo->mtime = date_dos2unix (WVAL (p, 14), WVAL (p, 12));
1459 finfo->wtime = finfo->mtime;
1461 #if DEBUG
1463 struct tm tm;
1465 GMTime(finfo->ctime,&tm);
1466 LOG(("ctime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
1468 GMTime(finfo->atime,&tm);
1469 LOG(("atime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
1471 GMTime(finfo->mtime,&tm);
1472 LOG(("mtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
1474 GMTime(finfo->wtime,&tm);
1475 LOG(("wtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
1477 #endif /* DEBUG */
1480 result = p + 28 + BVAL (p, 26);
1482 break;
1484 case 2: /* this is what OS/2 uses */
1486 #if DEBUG
1488 char buffer[255];
1490 memcpy(buffer,p + 31,sizeof(buffer)-1);
1491 buffer[sizeof(buffer)-1] = '\0';
1493 LOG(("type=%ld, name='%s'\n",level,buffer));
1495 #endif /* DEBUG */
1497 if (finfo != NULL)
1499 strlcpy (finfo->complete_path, p + 31, finfo->complete_path_size);
1500 finfo->len = strlen (finfo->complete_path);
1501 finfo->size = DVAL (p, 16);
1502 finfo->attr = BVAL (p, 24);
1503 finfo->ctime = date_dos2unix (WVAL (p, 6), WVAL (p, 4));
1504 finfo->atime = date_dos2unix (WVAL (p, 10), WVAL (p, 8));
1505 finfo->mtime = date_dos2unix (WVAL (p, 14), WVAL (p, 12));
1506 finfo->wtime = finfo->mtime;
1508 #if DEBUG
1510 struct tm tm;
1512 GMTime(finfo->ctime,&tm);
1513 LOG(("ctime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
1515 GMTime(finfo->atime,&tm);
1516 LOG(("atime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
1518 GMTime(finfo->mtime,&tm);
1519 LOG(("mtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
1521 GMTime(finfo->wtime,&tm);
1522 LOG(("wtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
1524 #endif /* DEBUG */
1527 result = p + 32 + BVAL (p, 30);
1529 break;
1531 case 260: /* NT uses this, but also accepts 2 */
1533 #if DEBUG
1535 char buffer[255];
1536 int len;
1538 len = min (DVAL (p+60, 0), sizeof(buffer)-1);
1540 memcpy(buffer,p+94,len);
1541 buffer[len] = '\0';
1543 LOG(("type=%ld, name='%s'\n",level,buffer));
1545 #endif /* DEBUG */
1547 result = p + WVAL (p, 0);
1549 if (finfo != NULL)
1551 int namelen;
1552 time_t swap;
1554 p += 4; /* next entry offset */
1555 p += 4; /* fileindex */
1556 finfo->ctime = interpret_long_date(p);
1557 p += 8;
1558 finfo->atime = interpret_long_date(p);
1559 p += 8;
1560 finfo->wtime = interpret_long_date(p);
1561 p += 8;
1562 finfo->mtime = interpret_long_date(p);
1563 p += 8;
1564 finfo->size = DVAL (p, 0);
1565 p += 8;
1566 p += 8; /* alloc size */
1567 finfo->attr = BVAL (p, 0);
1568 p += 4;
1569 namelen = min (DVAL (p, 0), SMB_MAXNAMELEN);
1570 p += 4;
1571 p += 4; /* EA size */
1572 p += 2; /* short name len? */
1573 p += 24; /* short name? */
1575 if(namelen > (int)finfo->complete_path_size-1)
1576 namelen = finfo->complete_path_size-1;
1578 /* If the modification time is not set, try to
1579 substitute the write time for it. */
1580 if(finfo->mtime == 0)
1581 finfo->mtime = finfo->wtime;
1583 /* Swap last modification time and last write time. */
1584 swap = finfo->mtime;
1585 finfo->mtime = finfo->wtime;
1586 finfo->wtime = swap;
1588 memcpy (finfo->complete_path, p, namelen);
1589 finfo->complete_path[namelen] = '\0';
1590 finfo->len = namelen;
1592 #if DEBUG
1594 struct tm tm;
1596 GMTime(finfo->ctime,&tm);
1597 LOG(("ctime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
1599 GMTime(finfo->atime,&tm);
1600 LOG(("atime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
1602 GMTime(finfo->wtime,&tm);
1603 LOG(("wtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
1605 GMTime(finfo->mtime,&tm);
1606 LOG(("mtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
1608 #endif /* DEBUG */
1611 break;
1613 default:
1615 if (finfo != NULL)
1617 /* I have to set times to 0 here, because I do not
1618 have specs about this for all info levels. */
1619 finfo->ctime = finfo->mtime = finfo->wtime = finfo->atime = 0;
1622 LOG (("Unknown long filename format %ld\n", level));
1624 result = p + WVAL (p, 0);
1626 break;
1629 return result;
1632 static int
1633 smb_proc_readdir_long (struct smb_server *server, char *path, int fpos, int cache_size, struct smb_dirent *entry)
1635 int max_matches = 512; /* this should actually be based on the max_buffer_size value */
1637 /* NT uses 260, OS/2 uses 2. Both accept 1. */
1638 int info_level = server->protocol < PROTOCOL_NT1 ? 1 : 260;
1640 char *p;
1641 int i;
1642 int first;
1643 int total_count = 0;
1644 struct smb_dirent *current_entry;
1646 char *resp_data;
1647 char *resp_param;
1648 int resp_data_len = 0;
1649 int resp_param_len = 0;
1651 int attribute = aSYSTEM | aHIDDEN | aDIR;
1652 int result;
1653 int error = 0;
1655 int ff_searchcount;
1656 int ff_eos = 0;
1657 int ff_dir_handle = 0;
1658 int ff_resume_key = 0;
1659 int loop_count = 0;
1661 unsigned char *outbuf = server->packet;
1663 int dirlen = strlen (path) + 2 + 1;
1664 char *mask;
1665 int masklen;
1667 ENTER();
1669 /* ZZZ experimental 'max_matches' adjustment */
1671 if(info_level == 260)
1672 max_matches = server->max_buffer_size / 360;
1673 else
1674 max_matches = server->max_buffer_size / 40;
1677 SHOWVALUE(server->max_buffer_size);
1678 SHOWVALUE(max_matches);
1680 mask = malloc (dirlen);
1681 if (mask == NULL)
1683 LOG (("Memory allocation failed\n"));
1684 error = (-ENOMEM);
1685 SHOWVALUE(error);
1686 goto out;
1689 strcpy (mask, path);
1690 strcat (mask, "\\*");
1691 masklen = strlen (mask);
1693 LOG (("SMB call lreaddir %ld @ %ld\n", cache_size, fpos));
1694 LOG ((" mask = %s\n", mask));
1696 resp_param = NULL;
1697 resp_data = NULL;
1699 retry:
1701 first = 1;
1702 total_count = 0;
1703 current_entry = entry;
1705 while (ff_eos == 0)
1707 loop_count++;
1708 if (loop_count > 200)
1710 LOG (("smb_proc_readdir_long: Looping in FIND_NEXT???\n"));
1711 error = -EIO;
1712 SHOWVALUE(error);
1713 break;
1716 memset (outbuf, 0, 39);
1718 smb_setup_header (server, SMBtrans2, 15, 5 + 12 + masklen + 1);
1720 WSET (outbuf, smb_tpscnt, 12 + masklen + 1);
1721 WSET (outbuf, smb_tdscnt, 0);
1722 WSET (outbuf, smb_mprcnt, 10);
1723 WSET (outbuf, smb_mdrcnt, server->max_buffer_size);
1724 WSET (outbuf, smb_msrcnt, 0);
1725 WSET (outbuf, smb_flags, 0);
1726 DSET (outbuf, smb_timeout, 0);
1727 WSET (outbuf, smb_pscnt, WVAL (outbuf, smb_tpscnt));
1728 WSET (outbuf, smb_psoff, ((SMB_BUF (outbuf) + 3) - outbuf) - 4);
1729 WSET (outbuf, smb_dscnt, 0);
1730 WSET (outbuf, smb_dsoff, 0);
1731 WSET (outbuf, smb_suwcnt, 1);
1732 WSET (outbuf, smb_setup0, first == 1 ? TRANSACT2_FINDFIRST : TRANSACT2_FINDNEXT);
1734 p = SMB_BUF (outbuf);
1735 (*p++) = 0; /* put in a null smb_name */
1736 (*p++) = 'D';
1737 (*p++) = ' '; /* this was added because OS/2 does it */
1739 if (first != 0)
1741 LOG (("first match\n"));
1742 WSET (p, 0, attribute); /* attribute */
1743 WSET (p, 2, max_matches); /* max count */
1744 WSET (p, 4, 8 + 4 + 2); /* resume required + close on end + continue */
1745 WSET (p, 6, info_level);
1746 DSET (p, 8, 0);
1748 else
1750 LOG (("next match; ff_dir_handle=0x%lx ff_resume_key=%ld mask='%s'\n", ff_dir_handle, ff_resume_key, mask));
1751 WSET (p, 0, ff_dir_handle);
1752 WSET (p, 2, max_matches); /* max count */
1753 WSET (p, 4, info_level);
1754 DSET (p, 6, ff_resume_key);
1755 WSET (p, 10, 8 + 4 + 2); /* resume required + close on end + continue */
1758 p += 12;
1760 if(masklen > 0)
1761 memcpy (p, mask, masklen);
1763 p += masklen;
1764 (*p++) = 0;
1765 (*p) = 0;
1767 result = smb_trans2_request (server, &resp_data_len, &resp_param_len, &resp_data, &resp_param);
1769 LOG (("smb_proc_readdir_long: smb_trans2_request returns %ld\n", result));
1771 if (result < 0)
1773 if (smb_retry (server))
1774 goto retry;
1776 LOG (("smb_proc_readdir_long: got error from trans2_request\n"));
1777 error = result;
1778 SHOWVALUE(error);
1779 break;
1782 /* Apparently, there is a bug in Windows 95 and friends which
1783 causes the directory read attempt to fail if you're asking
1784 for too much data too fast... */
1785 if(server->rcls == ERRSRV && server->err == ERRerror)
1787 SHOWMSG("ouch; delaying and retrying");
1789 Delay(TICKS_PER_SECOND / 5);
1791 continue;
1794 if (server->rcls != 0)
1796 LOG (("server->rcls = %ld err = %ld\n",server->rcls, server->err));
1797 error = smb_errno (server->rcls, server->err);
1798 SHOWVALUE(error);
1799 break;
1802 /* ZZZ bail out if this is empty. */
1803 if (resp_param == NULL)
1804 break;
1806 /* parse out some important return info */
1807 p = resp_param;
1808 if (first != 0)
1810 ff_dir_handle = WVAL (p, 0);
1811 ff_searchcount = WVAL (p, 2);
1812 ff_eos = WVAL (p, 4);
1814 else
1816 ff_searchcount = WVAL (p, 0);
1817 ff_eos = WVAL (p, 2);
1820 LOG (("received %ld entries (eos=%ld)\n",ff_searchcount, ff_eos));
1821 if (ff_searchcount == 0)
1822 break;
1824 /* ZZZ bail out if this is empty. */
1825 if (resp_data == NULL)
1826 break;
1828 /* point to the data bytes */
1829 p = resp_data;
1831 /* Now we are ready to parse smb directory entries. */
1832 for (i = 0; i < ff_searchcount; i++)
1834 if(i == ff_searchcount - 1)
1836 char * last_name;
1837 int len;
1839 ff_resume_key = DVAL(p, 0);
1841 smb_get_dirent_name(p,info_level,&last_name,&len);
1842 if(len > 0)
1844 #if DEBUG
1846 char buffer[SMB_MAXNAMELEN+1];
1848 memcpy(buffer,last_name,len);
1849 buffer[len] = '\0';
1851 LOG(("last name = '%s'\n",buffer));
1853 #endif /* DEBUG */
1855 if(len + 1 > dirlen)
1857 D(("increasing mask; old value = %ld new value = %ld",dirlen,len+1));
1859 if(mask != NULL)
1860 free (mask);
1862 dirlen = len + 1;
1863 SHOWVALUE(dirlen);
1865 mask = malloc (dirlen);
1866 if (mask == NULL)
1868 LOG (("smb_proc_readdir_long: Memory allocation failed\n"));
1870 error = -ENOMEM;
1872 SHOWVALUE(error);
1874 goto fail;
1878 memcpy (mask, last_name, len);
1879 mask[len] = '\0';
1880 masklen = len;
1882 else
1884 masklen = 0;
1888 if (total_count < fpos)
1890 p = smb_decode_long_dirent (p, NULL, info_level);
1892 LOG (("smb_proc_readdir: skipped entry; total_count = %ld, i = %ld, fpos = %ld\n",total_count, i, fpos));
1894 else if (total_count >= fpos + cache_size)
1896 p = smb_decode_long_dirent (p, NULL, info_level);
1898 LOG (("smb_proc_readdir: skipped entry; total_count = %ld, i = %ld, fpos = %ld\n",total_count, i, fpos));
1900 continue;
1902 else
1904 p = smb_decode_long_dirent (p, current_entry, info_level);
1906 current_entry += 1;
1909 total_count += 1;
1912 SHOWVALUE(ff_resume_key);
1914 if (resp_data != NULL)
1916 free (resp_data);
1917 resp_data = NULL;
1920 if (resp_param != NULL)
1922 free (resp_param);
1923 resp_param = NULL;
1926 first = 0;
1928 if (ff_searchcount > 0)
1929 loop_count = 0;
1932 fail:
1934 /* finished: not needed any more */
1935 if (mask != NULL)
1936 free (mask);
1938 if (resp_data != NULL)
1939 free (resp_data);
1941 if (resp_param != NULL)
1942 free (resp_param);
1944 out:
1946 if(error < 0)
1948 RETURN(error);
1949 return(error);
1951 else
1953 RETURN (total_count - fpos);
1954 return (total_count - fpos);
1959 smb_proc_readdir (struct smb_server *server, char *path, int fpos, int cache_size, struct smb_dirent *entry)
1961 int result;
1963 if (server->protocol >= PROTOCOL_LANMAN2)
1964 result = smb_proc_readdir_long (server, path, fpos, cache_size, entry);
1965 else
1966 result = smb_proc_readdir_short (server, path, fpos, cache_size, entry);
1968 return result;
1972 smb_proc_getattr_core (struct smb_server *server, const char *path, int len, struct smb_dirent *entry)
1974 int result;
1975 char *p;
1976 char *buf = server->packet;
1978 LOG (("smb_proc_getattr: %s\n", path));
1980 retry:
1982 p = smb_setup_header (server, SMBgetatr, 0, 2 + len);
1983 smb_encode_ascii (p, path, len);
1985 if ((result = smb_request_ok (server, SMBgetatr, 10, 0)) < 0)
1987 if (smb_retry (server))
1988 goto retry;
1990 goto out;
1993 entry->attr = WVAL (buf, smb_vwv0);
1995 /* The server only tells us 1 time */
1996 entry->ctime = entry->atime = entry->mtime = entry->wtime = local2utc (DVAL (buf, smb_vwv1));
1998 entry->size = DVAL (buf, smb_vwv3);
2000 #if DEBUG
2002 struct tm tm;
2004 GMTime(entry->ctime,&tm);
2005 LOG(("ctime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
2007 GMTime(entry->atime,&tm);
2008 LOG(("atime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
2010 GMTime(entry->mtime,&tm);
2011 LOG(("mtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
2013 GMTime(entry->wtime,&tm);
2014 LOG(("wtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
2016 #endif /* DEBUG */
2018 out:
2020 return result;
2023 /* smb_proc_getattrE: entry->fid must be valid */
2025 smb_proc_getattrE (struct smb_server *server, struct smb_dirent *entry)
2027 char *buf = server->packet;
2028 int result;
2030 smb_setup_header_exclusive (server, SMBgetattrE, 1, 0);
2031 WSET (buf, smb_vwv0, entry->fileid);
2033 if ((result = smb_request_ok (server, SMBgetattrE, 11, 0)) < 0)
2034 goto out;
2036 entry->ctime = date_dos2unix (WVAL (buf, smb_vwv1), WVAL (buf, smb_vwv0));
2037 entry->atime = date_dos2unix (WVAL (buf, smb_vwv3), WVAL (buf, smb_vwv2));
2038 entry->mtime = date_dos2unix (WVAL (buf, smb_vwv5), WVAL (buf, smb_vwv4));
2039 entry->wtime = entry->mtime;
2040 entry->size = DVAL (buf, smb_vwv6);
2041 entry->attr = WVAL (buf, smb_vwv10);
2043 #if DEBUG
2045 struct tm tm;
2047 GMTime(entry->ctime,&tm);
2048 LOG(("ctime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
2050 GMTime(entry->atime,&tm);
2051 LOG(("atime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
2053 GMTime(entry->mtime,&tm);
2054 LOG(("mtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
2056 GMTime(entry->wtime,&tm);
2057 LOG(("wtime = %ld-%02ld-%02ld %ld:%02ld:%02ld\n",tm.tm_year + 1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec));
2059 #endif /* DEBUG */
2061 out:
2063 return result;
2066 /* In core protocol, there is only 1 time to be set, we use
2067 entry->mtime, to make touch work. */
2069 smb_proc_setattr_core (struct smb_server *server, const char *path, int len, struct smb_dirent *new_finfo)
2071 char *p;
2072 char *buf = server->packet;
2073 int result;
2074 int local_time;
2076 retry:
2078 LOG (("smb_proc_setattr_core\n"));
2080 p = smb_setup_header (server, SMBsetatr, 8, 4 + len);
2081 WSET (buf, smb_vwv0, new_finfo->attr);
2082 local_time = utc2local (new_finfo->mtime);
2083 DSET (buf, smb_vwv1, local_time);
2084 p = smb_encode_ascii (p, path, len);
2085 (void) smb_encode_ascii (p, "", 0);
2087 if ((result = smb_request_ok (server, SMBsetatr, 0, 0)) < 0)
2089 if (smb_retry (server))
2090 goto retry;
2093 return result;
2096 /* smb_proc_setattrE: we do not retry here, because we rely on fid,
2097 which would not be valid after a retry. */
2099 smb_proc_setattrE (struct smb_server *server, word fid, struct smb_dirent *new_entry)
2101 char *buf = server->packet;
2102 word date, time_value;
2103 int result;
2105 LOG (("smb_proc_setattrE\n"));
2107 smb_setup_header_exclusive (server, SMBsetattrE, 7, 0);
2109 WSET (buf, smb_vwv0, fid);
2111 date_unix2dos (new_entry->ctime, &time_value, &date);
2112 WSET (buf, smb_vwv1, date);
2113 WSET (buf, smb_vwv2, time_value);
2115 date_unix2dos (new_entry->atime, &time_value, &date);
2116 WSET (buf, smb_vwv3, date);
2117 WSET (buf, smb_vwv4, time_value);
2119 date_unix2dos (new_entry->mtime, &time_value, &date);
2120 WSET (buf, smb_vwv5, date);
2121 WSET (buf, smb_vwv6, time_value);
2123 result = smb_request_ok_unlock (server, SMBsetattrE, 0, 0);
2125 return result;
2129 smb_proc_dskattr (struct smb_server *server, struct smb_dskattr *attr)
2131 int error;
2132 char *p;
2134 retry:
2136 smb_setup_header (server, SMBdskattr, 0, 0);
2138 if ((error = smb_request_ok (server, SMBdskattr, 5, 0)) < 0)
2140 if (smb_retry (server))
2141 goto retry;
2143 goto out;
2146 p = SMB_VWV (server->packet);
2147 p = smb_decode_word (p, &attr->total);
2148 p = smb_decode_word (p, &attr->allocblocks);
2149 p = smb_decode_word (p, &attr->blocksize);
2150 (void) smb_decode_word (p, &attr->free);
2152 out:
2154 return error;
2157 /*****************************************************************************
2159 * Mount/umount operations.
2161 ****************************************************************************/
2162 struct smb_prots
2164 enum smb_protocol prot;
2165 const char *name;
2168 /* smb_proc_reconnect: We expect the server to be locked, so that you
2169 can call the routine from within smb_retry. The socket must be
2170 created, like after a user-level socket()-call. It may not be
2171 connected. */
2172 static int
2173 smb_proc_reconnect (struct smb_server *server)
2175 static const struct smb_prots prots[] =
2177 {PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"}, /* Core Protocol */
2178 {PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"}, /* CorePlus */
2179 {PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"}, /* DOS LAN Manager 1.0 */
2180 {PROTOCOL_LANMAN1, "LANMAN1.0"}, /* LAN Manager 1.0 */
2181 {PROTOCOL_LANMAN2, "LM1.2X002"}, /* LAN Manager 2.0 */
2182 {PROTOCOL_NT1, "NT LM 0.12"}, /* NT LAN Manager */
2183 {PROTOCOL_NT1, "NT LANMAN 1.0"},
2186 const int num_prots = sizeof(prots) / sizeof(prots[0]);
2187 const char dev[] = "A:";
2188 int i, plength;
2189 const int default_max_buffer_size = 1024; /* Space needed for first request. */
2190 int given_max_xmit = server->mount_data.given_max_xmit;
2191 int result;
2192 word dialect_index;
2193 byte *p;
2194 unsigned char password[24];
2195 int password_len;
2196 unsigned char nt_password[24];
2197 int nt_password_len;
2198 unsigned char full_share[SMB_MAXNAMELEN+1];
2199 int full_share_len;
2200 byte *packet;
2201 word max_buffer_size;
2203 /* Reception buffer size (buffer is allocated below) is always as large as the
2204 * maximum transmission buffer size, and could be larger if the transmission
2205 * buffer size is smaller than 8000 bytes.
2207 if (server->max_recv <= 0)
2208 server->max_recv = given_max_xmit < 8000 ? 8000 : given_max_xmit;
2210 if ((result = smb_connect (server)) < 0) /* this is really a plain connect() call */
2212 LOG (("smb_proc_reconnect: could not smb_connect\n"));
2213 goto fail;
2216 /* Here we assume that the connection is valid */
2217 server->state = CONN_VALID;
2219 if (server->packet != NULL)
2220 free (server->packet);
2222 server->packet = malloc (server->max_recv);
2223 if (server->packet == NULL)
2225 LOG (("smb_proc_connect: No memory! Bailing out.\n"));
2226 result = -ENOMEM;
2227 goto fail;
2230 packet = server->packet;
2232 server->max_buffer_size = default_max_buffer_size;
2234 /* Prepend a NetBIOS header? */
2235 if(!server->raw_smb)
2237 /* Start with an RFC1002 session request packet. */
2238 p = packet + 4;
2240 p = smb_name_mangle (p, server->mount_data.server_name);
2241 p = smb_name_mangle (p, server->mount_data.client_name);
2243 smb_encode_smb_length (packet, (byte *) p - (byte *) (packet));
2245 packet[0] = 0x81; /* SESSION REQUEST */
2247 if ((result = smb_request (server)) < 0)
2249 LOG (("smb_proc_connect: Failed to send SESSION REQUEST.\n"));
2250 goto fail;
2253 if (packet[0] != 0x82)
2255 LOG (("smb_proc_connect: Did not receive positive response (err = %lx)\n",packet[0]));
2257 #if DEBUG
2259 smb_dump_packet (packet);
2261 #endif /* DEBUG */
2263 result = -EIO;
2264 goto fail;
2267 LOG (("smb_proc_connect: Passed SESSION REQUEST.\n"));
2270 /* Now we are ready to send a SMB Negotiate Protocol packet. */
2271 plength = 0;
2272 for (i = 0; i < num_prots ; i++)
2273 plength += strlen (prots[i].name) + 2;
2275 smb_setup_header (server, SMBnegprot, 0, plength);
2277 p = SMB_BUF (packet);
2279 for (i = 0; i < num_prots ; i++)
2280 p = smb_encode_dialect (p, prots[i].name, strlen (prots[i].name));
2282 LOG (("smb_proc_connect: Request SMBnegprot...\n"));
2283 if ((result = smb_request_ok (server, SMBnegprot, 1, -1)) < 0)
2285 LOG (("smb_proc_connect: Failure requesting SMBnegprot\n"));
2286 goto fail;
2289 LOG (("Verified!\n"));
2291 p = SMB_VWV (packet);
2293 smb_decode_word (p, &dialect_index);
2295 /* If the server does not support any of the listed
2296 * dialects, ist must return a dialect index of 0xFFFF.
2298 if(dialect_index > num_prots || dialect_index == 0xFFFFU)
2300 LOG (("smb_proc_connect: Unsupported dialect\n"));
2302 result = -EACCES;
2303 goto fail;
2306 server->protocol = prots[dialect_index].prot;
2308 LOG (("smb_proc_connect: Server wants %s protocol.\n",prots[dialect_index].name));
2310 if (server->protocol > PROTOCOL_LANMAN1)
2312 int user_len = strlen (server->mount_data.username)+1;
2313 dword server_sesskey;
2315 LOG (("smb_proc_connect: password = %s\n",server->mount_data.password));
2316 LOG (("smb_proc_connect: usernam = %s\n",server->mount_data.username));
2317 LOG (("smb_proc_connect: blkmode = %ld\n",WVAL (packet, smb_vwv5)));
2319 /* NT LAN Manager or newer. */
2320 if (server->protocol >= PROTOCOL_NT1)
2322 server->security_mode = BVAL(packet, smb_vwv1);
2323 max_buffer_size = DVAL (packet, smb_vwv3 + 1);
2324 server->max_raw_size = DVAL (packet, smb_vwv5 + 1);
2325 server_sesskey = DVAL (packet, smb_vwv7 + 1);
2326 server->capabilities = DVAL (packet, smb_vwv9 + 1);
2327 server->crypt_key_length = BVAL (packet, smb_vwv16 + 1);
2329 memcpy(server->crypt_key,SMB_BUF(packet),server->crypt_key_length);
2331 /* LAN Manager 2.0 or older */
2332 else
2334 word blkmode;
2336 server->security_mode = BVAL(packet, smb_vwv1);
2337 max_buffer_size = WVAL (packet, smb_vwv2);
2338 /* Maximum raw read/write size is fixed to 65535 bytes. */
2339 server->max_raw_size = 65535;
2340 blkmode = WVAL (packet, smb_vwv5);
2341 server_sesskey = DVAL (packet, smb_vwv6);
2343 /* Crypt key size is fixed to 8 bytes. */
2344 server->crypt_key_length = 8;
2346 memcpy(server->crypt_key,SMB_BUF(packet),server->crypt_key_length);
2348 /* We translate this into capabilities. According to the
2349 LAN Manager 1.x/2.0 documentation both bits 0+1 being set
2350 means the same thing as CAP_RAW_MODE being set. */
2351 if((blkmode & 3) == 3)
2352 server->capabilities = CAP_RAW_MODE;
2355 SHOWVALUE(server->security_mode);
2357 if(server->security_mode & NEGOTIATE_ENCRYPT_PASSWORDS)
2359 SHOWMSG("encrypted passwords required");
2361 memset(password,0,sizeof(password));
2362 strlcpy(password,server->mount_data.password,sizeof(password));
2364 smb_encrypt(password,server->crypt_key,password);
2365 password_len = 24;
2367 PRINTHEADER();
2368 PRINTF(("password: "));
2369 for(i = 0 ; i < 24 ; i++)
2370 PRINTF(("%02lx ",password[i]));
2371 PRINTF(("\n"));
2373 memset(nt_password,0,sizeof(nt_password));
2374 strlcpy(nt_password,server->mount_data.password,sizeof(nt_password));
2376 smb_nt_encrypt(nt_password,server->crypt_key,nt_password);
2377 nt_password_len = 24;
2379 PRINTHEADER();
2380 PRINTF(("nt_password: "));
2381 for(i = 0 ; i < 24 ; i++)
2382 PRINTF(("%02lx ",nt_password[i]));
2383 PRINTF(("\n"));
2385 PRINTHEADER();
2386 PRINTF(("crypt_key: "));
2387 for(i = 0 ; i < server->crypt_key_length ; i++)
2388 PRINTF(("%02lx ",server->crypt_key[i]));
2389 PRINTF(("\n"));
2391 else
2393 SHOWMSG("plain text passwords sufficient");
2395 password_len = strlen(server->mount_data.password)+1;
2396 nt_password_len = 0;
2399 /* If in share level security then don't send a password now */
2400 if((server->security_mode & NEGOTIATE_USER_SECURITY) == 0)
2402 SHOWMSG("share level security; zapping passwords");
2403 strcpy(password,"");
2404 password_len = 0;
2406 strcpy(nt_password,"");
2407 nt_password_len = 0;
2410 SHOWVALUE(password_len);
2411 SHOWVALUE(nt_password_len);
2413 LOG (("smb_proc_connect: workgroup = %s\n", server->mount_data.workgroup_name));
2415 /* NT LAN Manager or newer. */
2416 if (server->protocol >= PROTOCOL_NT1)
2418 #if !defined(__AROS__)
2419 char *OS_id = "AmigaOS";
2420 #else
2421 char *OS_id = "AROS";
2422 #endif
2423 char *client_id = "smbfs";
2425 SHOWMSG("server->protocol >= PROTOCOL_NT1");
2427 smb_setup_header (server, SMBsesssetupX, 13, user_len + password_len + nt_password_len + strlen (server->mount_data.workgroup_name)+1 + strlen (OS_id)+1 + strlen (client_id)+1);
2429 WSET (packet, smb_vwv0, 0xff);
2430 WSET (packet, smb_vwv2, given_max_xmit);
2431 WSET (packet, smb_vwv3, 2);
2432 WSET (packet, smb_vwv4, 0); /* server->pid */
2433 DSET (packet, smb_vwv5, server_sesskey);
2434 WSET (packet, smb_vwv7, password_len);
2435 WSET (packet, smb_vwv8, nt_password_len);
2436 DSET (packet, smb_vwv9, 0); /* reserved */
2437 DSET (packet, smb_vwv11, server->capabilities & 0x00800000); /* capabilities: Unix support. */
2439 p = SMB_BUF (packet);
2441 if(nt_password_len != 0)
2443 SHOWMSG("adding encrypted passwords");
2445 memcpy (p, password, password_len);
2446 p += password_len;
2448 memcpy (p, nt_password, nt_password_len);
2449 p += nt_password_len;
2451 else
2453 SHOWMSG("adding plain text password");
2455 memcpy (p, server->mount_data.password, password_len);
2456 p += password_len;
2459 memcpy (p, server->mount_data.username, user_len);
2460 p += user_len;
2462 strcpy (p, server->mount_data.workgroup_name);
2463 p += strlen (p) + 1;
2465 strcpy (p, OS_id);
2466 p += strlen (p) + 1;
2468 strcpy (p, client_id);
2470 /* LAN Manager 2.0 or older */
2471 else
2473 smb_setup_header (server, SMBsesssetupX, 10, user_len + password_len);
2475 WSET (packet, smb_vwv0, 0xff); /* No further ANDX command */
2476 WSET (packet, smb_vwv1, 0); /* ANDX offset = 0 */
2478 WSET (packet, smb_vwv2, given_max_xmit); /* maximum buffer size */
2479 WSET (packet, smb_vwv3, 2); /* maximum mpx count; should be copied from server */
2480 WSET (packet, smb_vwv4, 0); /* server->pid */
2481 DSET (packet, smb_vwv5, server_sesskey);
2482 WSET (packet, smb_vwv7, password_len); /* case sensitive password length */
2483 WSET (packet, smb_vwv8, 0); /* offset to encrypted password */
2485 p = SMB_BUF (packet);
2486 memcpy (p, server->mount_data.password, password_len);
2488 p += password_len;
2489 memcpy (p, server->mount_data.username, user_len);
2492 if ((result = smb_request_ok (server, SMBsesssetupX, 3, 0)) < 0)
2494 LOG (("smb_proc_connect: SMBsessetupX failed\n"));
2495 goto fail;
2498 smb_decode_word (packet + 32, &(server->server_uid));
2500 else
2502 max_buffer_size = 0;
2503 server->capabilities = 0;
2505 password_len = strlen(server->mount_data.password)+1;
2507 nt_password_len = 0;
2510 if(nt_password_len > 0)
2512 strlcpy(full_share,"//",sizeof(full_share));
2513 strlcat(full_share,server->mount_data.server_name,sizeof(full_share));
2514 strlcat(full_share,"/",sizeof(full_share));
2515 strlcat(full_share,server->mount_data.service,sizeof(full_share));
2517 full_share_len = strlen(full_share);
2519 for(i = 0 ; i < full_share_len ; i++)
2521 if(full_share[i] == '/')
2522 full_share[i] = '\\';
2525 StringToUpper(full_share);
2527 SHOWSTRING(full_share);
2529 smb_setup_header (server, SMBtconX, 4, password_len + full_share_len+1 + strlen(dev)+1);
2531 WSET (packet, smb_vwv0, 0xFF);
2532 WSET (packet, smb_vwv3, password_len);
2534 p = SMB_BUF (packet);
2536 if(nt_password_len > 0)
2537 memcpy(p,password,password_len);
2538 else
2539 memcpy (p, server->mount_data.password, password_len);
2541 p += password_len;
2543 memcpy(p,full_share,full_share_len+1);
2544 p += full_share_len+1;
2546 strcpy(p,dev);
2548 if ((result = smb_request_ok (server, SMBtconX, 3, 0)) < 0)
2550 SHOWVALUE(SMB_WCT(packet));
2552 LOG (("smb_proc_connect: SMBtconX not verified.\n"));
2553 goto fail;
2556 SHOWVALUE(SMB_WCT(packet));
2558 /* Changed, max_buffer_size hasn't been updated if a tconX message was send instead of tcon. */
2559 if (max_buffer_size != 0)
2560 server->max_buffer_size = max_buffer_size;
2562 server->tid = WVAL(packet,smb_tid);
2564 else
2566 word decoded_max_xmit;
2568 /* Fine! We have a connection, send a tcon message. */
2569 smb_setup_header (server, SMBtcon, 0, 6 + strlen (server->mount_data.service) + strlen (server->mount_data.password) + strlen (dev));
2571 p = SMB_BUF (packet);
2572 p = smb_encode_ascii (p, server->mount_data.service, strlen (server->mount_data.service));
2573 p = smb_encode_ascii (p, server->mount_data.password, strlen (server->mount_data.password));
2574 (void) smb_encode_ascii (p, dev, strlen (dev));
2576 if ((result = smb_request_ok (server, SMBtcon, 2, 0)) < 0)
2578 LOG (("smb_proc_connect: SMBtcon not verified.\n"));
2579 goto fail;
2582 LOG (("OK! Managed to set up SMBtcon!\n"));
2584 p = SMB_VWV (packet);
2585 p = smb_decode_word (p, &decoded_max_xmit);
2587 server->max_buffer_size = decoded_max_xmit;
2589 SHOWVALUE(server->max_buffer_size);
2591 /* Added by Brian Willette - We were ignoring the server's initial
2592 maxbuf value */
2593 if (max_buffer_size != 0 && server->max_buffer_size > max_buffer_size)
2594 server->max_buffer_size = max_buffer_size;
2596 (void) smb_decode_word (p, &server->tid);
2599 SHOWVALUE(server->max_buffer_size);
2601 /* Ok, everything is fine. max_buffer_size does not include
2602 the SMB session header of 4 bytes. */
2603 if (server->max_buffer_size < 65535 - 4)
2604 server->max_buffer_size += 4;
2606 /* Changed, max_buffer_size hasn't been updated if a tconX message was send instead of tcon. */
2607 if (server->max_buffer_size > given_max_xmit)
2608 server->max_buffer_size = given_max_xmit;
2610 LOG (("max_buffer_size = %ld, tid = %ld\n", server->max_buffer_size, server->tid));
2612 LOG (("smb_proc_connect: Normal exit\n"));
2614 return 0;
2616 fail:
2618 server->state = CONN_INVALID;
2620 return result;
2623 /* smb_proc_reconnect: server->packet is allocated with
2624 server->max_buffer_size bytes if and only if we return >= 0 */
2626 smb_proc_connect (struct smb_server *server)
2628 int result;
2630 result = smb_proc_reconnect (server);
2632 if ((result < 0) && (server->packet != NULL))
2634 free (server->packet);
2635 server->packet = NULL;
2638 return result;
2641 /* error code stuff - put together by Merik Karman
2642 merik -at- blackadder -dot- dsh -dot- oz -dot- au */
2643 typedef struct
2645 char *name;
2646 int code;
2647 char *message;
2648 } err_code_struct;
2650 /* Dos Error Messages */
2651 static const err_code_struct dos_msgs[] =
2653 {"ERRbadfunc", 1, "Invalid function"},
2654 {"ERRbadfile", 2, "File not found"},
2655 {"ERRbadpath", 3, "Directory invalid"},
2656 {"ERRnofids", 4, "No file descriptors available"},
2657 {"ERRnoaccess", 5, "Access denied"},
2658 {"ERRbadfid", 6, "Invalid file handle"},
2659 {"ERRbadmcb", 7, "Memory control blocks destroyed"},
2660 {"ERRnomem", 8, "Insufficient server memory to perform the requested function"},
2661 {"ERRbadmem", 9, "Invalid memory block address"},
2662 {"ERRbadenv", 10, "Invalid environment"},
2663 {"ERRbadformat", 11, "Invalid format"},
2664 {"ERRbadaccess", 12, "Invalid open mode"},
2665 {"ERRbaddata", 13, "Invalid data"},
2666 {"ERR", 14, "reserved"},
2667 {"ERRbaddrive", 15, "Invalid drive specified"},
2668 {"ERRremcd", 16, "A Delete Directory request attempted to remove the server's current directory"},
2669 {"ERRdiffdevice", 17, "Not same device"},
2670 {"ERRnofiles", 18, "A File Search command can find no more files matching the specified criteria"},
2671 {"ERRbadshare", 32, "The sharing mode specified for an Open conflicts with existing FIDs on the file"},
2672 {"ERRlock", 33, "A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process"},
2673 {"ERRnosuchshare", 67, "Share name not found"},
2674 {"ERRfilexists", 80, "The file named in a Create Directory, Make New File or Link request already exists"},
2675 {"ERRpaused", 81, "The server is temporarily paused"},
2676 {"ERRtimeout", 88, "The requested operation on a named pipe or an I/O device has timed out"},
2677 {"ERRnoresource", 89, "No resources currently available for this SMB request"},
2678 {"ERRtoomanyuids", 90, "Too many UIDs active for this SMB connection"},
2679 {"ERRbaduid", 91, "The UID supplied is not known to the session, or the user identified by the UID does not have sufficient privileges"},
2680 {"ERRbadpipe", 230, "Pipe invalid"},
2681 {"ERRpipebusy", 231, "All instances of the requested pipe are busy"},
2682 {"ERRpipeclosing", 232, "Pipe close in progress"},
2683 {"ERRnotconnected", 233, "No process on other end of pipe"},
2684 {"ERRmoredata", 234, "There is more data to be returned"},
2685 {"ERROR_EAS_DIDNT_FIT", 275, "Either there are no extended attributes, or the available extended attributes did not fit into the response"},
2686 {"ERROR_EAS_NOT_SUPPORTED", 282, "The server file system does not support Extended Attributes"},
2688 {NULL, -1, NULL}
2691 /* Server Error Messages */
2692 static const err_code_struct server_msgs[] =
2694 {"ERRerror", 1, "Non-specific error code"},
2695 {"ERRbadpw", 2, "Bad password - name/password pair in a Tree Connect or Session Setup are invalid"},
2696 {"ERRbadtype", 3, "reserved"},
2697 {"ERRaccess", 4, "The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID"},
2698 {"ERRinvnid", 5, "The tree ID (TID) specified in a command was invalid"},
2699 {"ERRinvnetname", 6, "Invalid network name in tree connect"},
2700 {"ERRinvdevice", 7, "Invalid device - printer request made to non-printer connection or non-printer request made to printer connection"},
2701 {"ERRqfull", 49, "Print queue full (files) -- returned by open print file"},
2702 {"ERRqtoobig", 50, "Print queue full -- no space"},
2703 {"ERRqeof", 51, "EOF on print queue dump"},
2704 {"ERRinvpfid", 52, "Invalid print file FID"},
2705 {"ERRsmbcmd", 64, "The server did not recognize the command received"},
2706 {"ERRsrverror", 65, "The server encountered an internal error, e.g., system file unavailable"},
2707 {"ERRfilespecs", 67, "The file handle (FID) and pathname parameters contained an invalid combination of values"},
2708 {"ERRreserved", 68, "reserved"},
2709 {"ERRbadpermits", 69, "The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute"},
2710 {"ERRreserved", 70, "reserved"},
2711 {"ERRsetattrmode", 71, "The attribute mode in the Set File Attribute request is invalid"},
2712 {"ERRpaused", 81, "Server is paused"},
2713 {"ERRmsgoff", 82, "Not receiving messages"},
2714 {"ERRnoroom", 83, "No room to buffer message"},
2715 {"ERRrmuns", 87, "Too many remote user names"},
2716 {"ERRtimeout", 88, "Operation timed out"},
2717 {"ERRnoresource", 89, "No resources currently available for request"},
2718 {"ERRtoomanyuids", 90, "Too many UIDs active on this session"},
2719 {"ERRbaduid", 91, "The UID is not known as a valid ID on this session"},
2720 {"ERRusempx", 250, "Temp unable to support Raw, use MPX mode"},
2721 {"ERRusestd", 251, "Temp unable to support Raw, use standard read/write"},
2722 {"ERRcontmpx", 252, "Continue in MPX mode"},
2723 {"ERRreserved", 253, "reserved"},
2724 {"ERRbadPW", 254, "Invalid password"},
2725 {"ERRaccountExpired", 2239, "User account on the target machine is disabled or has expired"},
2726 {"ERRbadClient", 2240, "The client does not have permission to access this server"},
2727 {"ERRbadLogonTime", 2241, "Access to the server is not permitted at this time"},
2728 {"ERRpasswordExpired", 2242, "The user's password has expired"},
2729 {"ERRnosupport", 0xFFFF, "Function not supported"},
2731 {NULL, -1, NULL}
2734 /* Hard Error Messages */
2735 static const err_code_struct hard_msgs[] =
2737 {"ERRnowrite", 19, "Attempt to write on write-protected diskette"},
2738 {"ERRbadunit", 20, "Unknown unit"},
2739 {"ERRnotready", 21, "Drive not ready"},
2740 {"ERRbadcmd", 22, "Unknown command"},
2741 {"ERRdata", 23, "Data error (CRC)"},
2742 {"ERRbadreq", 24, "Bad request structure length"},
2743 {"ERRseek", 25, "Seek error"},
2744 {"ERRbadmedia", 26, "Unknown media type"},
2745 {"ERRbadsector", 27, "Sector not found"},
2746 {"ERRnopaper", 28, "Printer out of paper"},
2747 {"ERRwrite", 29, "Write fault"},
2748 {"ERRread", 30, "Read fault"},
2749 {"ERRgeneral", 31, "General failure"},
2750 {"ERRbadshare", 32, "A open conflicts with an existing open"},
2751 {"ERRlock", 33, "A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process"},
2752 {"ERRwrongdisk", 34, "The wrong disk was found in a drive"},
2753 {"ERRFCBUnavail", 35, "No FCBs are available to process request"},
2754 {"ERRsharebufexc", 36, "A sharing buffer has been exceeded"},
2755 {"ERRdiskfull", 39, "The file system is full"},
2757 {NULL, -1, NULL}
2760 typedef struct
2762 int code;
2763 char *class;
2764 const err_code_struct *err_msgs;
2765 } err_class_struct;
2767 static const err_class_struct err_classes[] =
2769 { 0, "SUCCESS", NULL },
2770 { 0x01, "ERRDOS", dos_msgs },
2771 { 0x02, "ERRSRV", server_msgs },
2772 { 0x03, "ERRHRD", hard_msgs },
2773 { 0x04, "ERRXOS", NULL },
2774 { 0xE1, "ERRRMX1", NULL },
2775 { 0xE2, "ERRRMX2", NULL },
2776 { 0xE3, "ERRRMX3", NULL },
2777 { 0xFF, "ERRCMD", NULL },
2779 { -1, NULL, NULL }
2782 static void
2783 smb_printerr (int class, int num)
2785 int i, j;
2786 err_code_struct *err;
2788 for (i = 0; err_classes[i].class; i++)
2790 if (err_classes[i].code != class)
2791 continue;
2793 if (!err_classes[i].err_msgs)
2795 ReportError("%s - %ld.", err_classes[i].class, num);
2797 LOG (("%s - %ld\n", err_classes[i].class, num));
2798 return;
2801 err = (err_code_struct *)err_classes[i].err_msgs;
2803 for (j = 0; err[j].name; j++)
2805 if (num != err[j].code)
2806 continue;
2808 ReportError ("%s - %s (%s).", err_classes[i].class, err[j].name, err[j].message);
2810 LOG (("%s - %s (%s)\n",err_classes[i].class, err[j].name,err[j].message));
2811 return;
2815 ReportError ("Unknown error - (%ld, %ld).", class, num);
2817 LOG (("Unknown error - (%ld, %ld)\n", class, num));