Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
netmisc.c
Go to the documentation of this file.
1 /*
2  * fs/cifs/netmisc.c
3  *
4  * Copyright (c) International Business Machines Corp., 2002,2008
5  * Author(s): Steve French ([email protected])
6  *
7  * Error mapping routines from Samba libsmb/errormap.c
8  * Copyright (C) Andrew Tridgell 2001
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
18  * the GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23  */
24 
25 #include <linux/net.h>
26 #include <linux/string.h>
27 #include <linux/in.h>
28 #include <linux/ctype.h>
29 #include <linux/fs.h>
30 #include <asm/div64.h>
31 #include <asm/byteorder.h>
32 #include <linux/inet.h>
33 #include "cifsfs.h"
34 #include "cifspdu.h"
35 #include "cifsglob.h"
36 #include "cifsproto.h"
37 #include "smberr.h"
38 #include "cifs_debug.h"
39 #include "nterr.h"
40 
44 };
45 
46 static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
47  {ERRbadfunc, -EINVAL},
48  {ERRbadfile, -ENOENT},
49  {ERRbadpath, -ENOTDIR},
50  {ERRnofids, -EMFILE},
51  {ERRnoaccess, -EACCES},
52  {ERRbadfid, -EBADF},
53  {ERRbadmcb, -EIO},
54  {ERRnomem, -ENOMEM},
55  {ERRbadmem, -EFAULT},
56  {ERRbadenv, -EFAULT},
57  {ERRbadformat, -EINVAL},
58  {ERRbadaccess, -EACCES},
59  {ERRbaddata, -EIO},
60  {ERRbaddrive, -ENXIO},
61  {ERRremcd, -EACCES},
62  {ERRdiffdevice, -EXDEV},
63  {ERRnofiles, -ENOENT},
64  {ERRwriteprot, -EROFS},
65  {ERRbadshare, -ETXTBSY},
66  {ERRlock, -EACCES},
67  {ERRunsup, -EINVAL},
69  {ERRfilexists, -EEXIST},
70  {ERRinvparm, -EINVAL},
71  {ERRdiskfull, -ENOSPC},
72  {ERRinvname, -ENOENT},
75  {ERRnotlocked, -ENOLCK},
80  {ErrQuota, -EDQUOT},
81  {ErrNotALink, -ENOLINK},
85  {0, 0}
86 };
87 
88 static const struct smb_to_posix_error mapping_table_ERRSRV[] = {
89  {ERRerror, -EIO},
90  {ERRbadpw, -EACCES}, /* was EPERM */
91  {ERRbadtype, -EREMOTE},
92  {ERRaccess, -EACCES},
93  {ERRinvtid, -ENXIO},
94  {ERRinvnetname, -ENXIO},
95  {ERRinvdevice, -ENXIO},
96  {ERRqfull, -ENOSPC},
97  {ERRqtoobig, -ENOSPC},
98  {ERRqeof, -EIO},
99  {ERRinvpfid, -EBADF},
100  {ERRsmbcmd, -EBADRQC},
101  {ERRsrverror, -EIO},
102  {ERRbadBID, -EIO},
103  {ERRfilespecs, -EINVAL},
104  {ERRbadLink, -EIO},
105  {ERRbadpermits, -EINVAL},
106  {ERRbadPID, -ESRCH},
108  {ERRpaused, -EHOSTDOWN},
109  {ERRmsgoff, -EHOSTDOWN},
110  {ERRnoroom, -ENOSPC},
111  {ERRrmuns, -EUSERS},
112  {ERRtimeout, -ETIME},
115  {ERRbaduid, -EACCES},
116  {ERRusempx, -EIO},
117  {ERRusestd, -EIO},
119  {ERRnoSuchUser, -EACCES},
120 /* {ERRaccountexpired, -EACCES},
121  {ERRbadclient, -EACCES},
122  {ERRbadLogonTime, -EACCES},
123  {ERRpasswordExpired, -EACCES},*/
125  {ERRbadclient, -EACCES},
128 
129  {ERRnosupport, -EINVAL},
130  {0, 0}
131 };
132 
133 static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
134  {0, 0}
135 };
136 
137 /*
138  * Convert a string containing text IPv4 or IPv6 address to binary form.
139  *
140  * Returns 0 on failure.
141  */
142 static int
143 cifs_inet_pton(const int address_family, const char *cp, int len, void *dst)
144 {
145  int ret = 0;
146 
147  /* calculate length by finding first slash or NULL */
148  if (address_family == AF_INET)
149  ret = in4_pton(cp, len, dst, '\\', NULL);
150  else if (address_family == AF_INET6)
151  ret = in6_pton(cp, len, dst , '\\', NULL);
152 
153  cFYI(DBG2, "address conversion returned %d for %*.*s",
154  ret, len, len, cp);
155  if (ret > 0)
156  ret = 1;
157  return ret;
158 }
159 
160 /*
161  * Try to convert a string to an IPv4 address and then attempt to convert
162  * it to an IPv6 address if that fails. Set the family field if either
163  * succeeds. If it's an IPv6 address and it has a '%' sign in it, try to
164  * treat the part following it as a numeric sin6_scope_id.
165  *
166  * Returns 0 on failure.
167  */
168 int
169 cifs_convert_address(struct sockaddr *dst, const char *src, int len)
170 {
171  int rc, alen, slen;
172  const char *pct;
173  char scope_id[13];
174  struct sockaddr_in *s4 = (struct sockaddr_in *) dst;
175  struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst;
176 
177  /* IPv4 address */
178  if (cifs_inet_pton(AF_INET, src, len, &s4->sin_addr.s_addr)) {
179  s4->sin_family = AF_INET;
180  return 1;
181  }
182 
183  /* attempt to exclude the scope ID from the address part */
184  pct = memchr(src, '%', len);
185  alen = pct ? pct - src : len;
186 
187  rc = cifs_inet_pton(AF_INET6, src, alen, &s6->sin6_addr.s6_addr);
188  if (!rc)
189  return rc;
190 
191  s6->sin6_family = AF_INET6;
192  if (pct) {
193  /* grab the scope ID */
194  slen = len - (alen + 1);
195  if (slen <= 0 || slen > 12)
196  return 0;
197  memcpy(scope_id, pct + 1, slen);
198  scope_id[slen] = '\0';
199 
200  rc = kstrtouint(scope_id, 0, &s6->sin6_scope_id);
201  rc = (rc == 0) ? 1 : 0;
202  }
203 
204  return rc;
205 }
206 
207 int
208 cifs_set_port(struct sockaddr *addr, const unsigned short int port)
209 {
210  switch (addr->sa_family) {
211  case AF_INET:
212  ((struct sockaddr_in *)addr)->sin_port = htons(port);
213  break;
214  case AF_INET6:
215  ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
216  break;
217  default:
218  return 0;
219  }
220  return 1;
221 }
222 
223 int
224 cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
225  const unsigned short int port)
226 {
227  if (!cifs_convert_address(dst, src, len))
228  return 0;
229  return cifs_set_port(dst, port);
230 }
231 
232 /*****************************************************************************
233 convert a NT status code to a dos class/code
234  *****************************************************************************/
235 /* NT status -> dos error map */
236 static const struct {
240 } ntstatus_to_dos_map[] = {
241  {
263 /* { This NT error code was 'sqashed'
264  from NT_STATUS_MORE_PROCESSING_REQUIRED to NT_STATUS_OK
265  during the session setup } */
266  {
278 /* { This NT error code was 'sqashed'
279  from NT_STATUS_ACCESS_DENIED to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE
280  during the session setup } */
281  {
290  ERRDOS, 158, NT_STATUS_NOT_LOCKED}, {
299  /* mapping changed since shell does lookup on * expects FileNotFound */
312  ERRDOS, 23, NT_STATUS_CRC_ERROR}, {
349 /* { This NT error code was 'sqashed'
350  from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE
351  during the session setup } */
352  {
353  ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, { /* could map to 2238 */
359 /* { This NT error code was 'sqashed'
360  from NT_STATUS_WRONG_PASSWORD to NT_STATUS_LOGON_FAILURE
361  during the session setup } */
362  {
384  ERRDOS, 112, NT_STATUS_DISK_FULL}, {
411 /* { This NT error code was 'sqashed'
412  from NT_STATUS_INSUFFICIENT_RESOURCES to
413  NT_STATUS_INSUFF_SERVER_RESOURCES during the session setup } */
414  {
442  ERRDOS, 121, NT_STATUS_IO_TIMEOUT}, {
517  ERRDOS, 203, 0xc0000100}, {
524  ERRDOS, 2401, NT_STATUS_FILES_OPEN}, {
592  ERRDOS, 109, NT_STATUS_PIPE_BROKEN}, {
627  ERRHRD, ERRgeneral, 0xc000016e}, {
628  ERRHRD, ERRgeneral, 0xc000016f}, {
629  ERRHRD, ERRgeneral, 0xc0000170}, {
630  ERRHRD, ERRgeneral, 0xc0000171}, {
638  ERRHRD, ERRgeneral, 0xc0000179}, {
654  ERRDOS, 19, NT_STATUS_TOO_LATE}, {
656 /* { This NT error code was 'sqashed'
657  from NT_STATUS_NO_TRUST_SAM_ACCOUNT to
658  NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE during the session setup } */
659  {
676 /* { This NT error code was 'sqashed'
677  from NT_STATUS_DOMAIN_TRUST_INCONSISTENT to NT_STATUS_LOGON_FAILURE
678  during the session setup } */
679  {
754  ERRHRD, ERRgeneral, 0xc000024a}, {
755  ERRHRD, ERRgeneral, 0xc000024b}, {
756  ERRHRD, ERRgeneral, 0xc000024c}, {
757  ERRHRD, ERRgeneral, 0xc000024d}, {
758  ERRHRD, ERRgeneral, 0xc000024e}, {
759  ERRHRD, ERRgeneral, 0xc000024f}, {
773  ERRHRD, ERRgeneral, 0xc000025d}, {
784  ERRDOS, 21, 0xc000026e}, {
785  ERRDOS, 161, 0xc0000281}, {
786  ERRDOS, ERRnoaccess, 0xc000028a}, {
787  ERRDOS, ERRnoaccess, 0xc000028b}, {
788  ERRHRD, ERRgeneral, 0xc000028c}, {
789  ERRDOS, ERRnoaccess, 0xc000028d}, {
790  ERRDOS, ERRnoaccess, 0xc000028e}, {
791  ERRDOS, ERRnoaccess, 0xc000028f}, {
792  ERRDOS, ERRnoaccess, 0xc0000290}, {
793  ERRDOS, ERRbadfunc, 0xc000029c}, {
795  ERRDOS, ERRinvlevel, 0x007c0001}, };
796 
797 /*****************************************************************************
798  Print an error message from the status code
799  *****************************************************************************/
800 static void
801 cifs_print_status(__u32 status_code)
802 {
803  int idx = 0;
804 
805  while (nt_errs[idx].nt_errstr != NULL) {
806  if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) ==
807  (status_code & 0xFFFFFF)) {
808  printk(KERN_NOTICE "Status code returned 0x%08x %s\n",
809  status_code, nt_errs[idx].nt_errstr);
810  }
811  idx++;
812  }
813  return;
814 }
815 
816 
817 static void
818 ntstatus_to_dos(__u32 ntstatus, __u8 *eclass, __u16 *ecode)
819 {
820  int i;
821  if (ntstatus == 0) {
822  *eclass = 0;
823  *ecode = 0;
824  return;
825  }
826  for (i = 0; ntstatus_to_dos_map[i].ntstatus; i++) {
827  if (ntstatus == ntstatus_to_dos_map[i].ntstatus) {
828  *eclass = ntstatus_to_dos_map[i].dos_class;
829  *ecode = ntstatus_to_dos_map[i].dos_code;
830  return;
831  }
832  }
833  *eclass = ERRHRD;
834  *ecode = ERRgeneral;
835 }
836 
837 int
838 map_smb_to_linux_error(char *buf, bool logErr)
839 {
840  struct smb_hdr *smb = (struct smb_hdr *)buf;
841  unsigned int i;
842  int rc = -EIO; /* if transport error smb error may not be set */
843  __u8 smberrclass;
844  __u16 smberrcode;
845 
846  /* BB if NT Status codes - map NT BB */
847 
848  /* old style smb error codes */
849  if (smb->Status.CifsError == 0)
850  return 0;
851 
852  if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
853  /* translate the newer STATUS codes to old style SMB errors
854  * and then to POSIX errors */
855  __u32 err = le32_to_cpu(smb->Status.CifsError);
856  if (logErr && (err != (NT_STATUS_MORE_PROCESSING_REQUIRED)))
857  cifs_print_status(err);
858  else if (cifsFYI & CIFS_RC)
859  cifs_print_status(err);
860  ntstatus_to_dos(err, &smberrclass, &smberrcode);
861  } else {
862  smberrclass = smb->Status.DosError.ErrorClass;
863  smberrcode = le16_to_cpu(smb->Status.DosError.Error);
864  }
865 
866  /* old style errors */
867 
868  /* DOS class smb error codes - map DOS */
869  if (smberrclass == ERRDOS) {
870  /* 1 byte field no need to byte reverse */
871  for (i = 0;
872  i <
873  sizeof(mapping_table_ERRDOS) /
874  sizeof(struct smb_to_posix_error); i++) {
875  if (mapping_table_ERRDOS[i].smb_err == 0)
876  break;
877  else if (mapping_table_ERRDOS[i].smb_err ==
878  smberrcode) {
879  rc = mapping_table_ERRDOS[i].posix_code;
880  break;
881  }
882  /* else try next error mapping one to see if match */
883  }
884  } else if (smberrclass == ERRSRV) {
885  /* server class of error codes */
886  for (i = 0;
887  i <
888  sizeof(mapping_table_ERRSRV) /
889  sizeof(struct smb_to_posix_error); i++) {
890  if (mapping_table_ERRSRV[i].smb_err == 0)
891  break;
892  else if (mapping_table_ERRSRV[i].smb_err ==
893  smberrcode) {
894  rc = mapping_table_ERRSRV[i].posix_code;
895  break;
896  }
897  /* else try next error mapping to see if match */
898  }
899  }
900  /* else ERRHRD class errors or junk - return EIO */
901 
902  cFYI(1, "Mapping smb error code 0x%x to POSIX err %d",
903  le32_to_cpu(smb->Status.CifsError), rc);
904 
905  /* generic corrective action e.g. reconnect SMB session on
906  * ERRbaduid could be added */
907 
908  return rc;
909 }
910 
911 /*
912  * calculate the size of the SMB message based on the fixed header
913  * portion, the number of word parameters and the data portion of the message
914  */
915 unsigned int
917 {
918  struct smb_hdr *ptr = (struct smb_hdr *)buf;
919  return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
920  2 /* size of the bcc field */ + get_bcc(ptr));
921 }
922 
923 /* The following are taken from fs/ntfs/util.c */
924 
925 #define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000)
926 
927 /*
928  * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units)
929  * into Unix UTC (based 1970-01-01, in seconds).
930  */
931 struct timespec
933 {
934  struct timespec ts;
935  /* BB what about the timezone? BB */
936 
937  /* Subtract the NTFS time offset, then convert to 1s intervals. */
938  u64 t;
939 
940  t = le64_to_cpu(ntutc) - NTFS_TIME_OFFSET;
941  ts.tv_nsec = do_div(t, 10000000) * 100;
942  ts.tv_sec = t;
943  return ts;
944 }
945 
946 /* Convert the Unix UTC into NT UTC. */
947 u64
949 {
950  /* Convert to 100ns intervals and then add the NTFS time offset. */
951  return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET;
952 }
953 
954 static int total_days_of_prev_months[] =
955 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
956 
957 struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset)
958 {
959  struct timespec ts;
960  int sec, min, days, month, year;
961  u16 date = le16_to_cpu(le_date);
962  u16 time = le16_to_cpu(le_time);
963  SMB_TIME *st = (SMB_TIME *)&time;
964  SMB_DATE *sd = (SMB_DATE *)&date;
965 
966  cFYI(1, "date %d time %d", date, time);
967 
968  sec = 2 * st->TwoSeconds;
969  min = st->Minutes;
970  if ((sec > 59) || (min > 59))
971  cERROR(1, "illegal time min %d sec %d", min, sec);
972  sec += (min * 60);
973  sec += 60 * 60 * st->Hours;
974  if (st->Hours > 24)
975  cERROR(1, "illegal hours %d", st->Hours);
976  days = sd->Day;
977  month = sd->Month;
978  if ((days > 31) || (month > 12)) {
979  cERROR(1, "illegal date, month %d day: %d", month, days);
980  if (month > 12)
981  month = 12;
982  }
983  month -= 1;
984  days += total_days_of_prev_months[month];
985  days += 3652; /* account for difference in days between 1980 and 1970 */
986  year = sd->Year;
987  days += year * 365;
988  days += (year/4); /* leap year */
989  /* generalized leap year calculation is more complex, ie no leap year
990  for years/100 except for years/400, but since the maximum number for DOS
991  year is 2**7, the last year is 1980+127, which means we need only
992  consider 2 special case years, ie the years 2000 and 2100, and only
993  adjust for the lack of leap year for the year 2100, as 2000 was a
994  leap year (divisable by 400) */
995  if (year >= 120) /* the year 2100 */
996  days = days - 1; /* do not count leap year for the year 2100 */
997 
998  /* adjust for leap year where we are still before leap day */
999  if (year != 120)
1000  days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0);
1001  sec += 24 * 60 * 60 * days;
1002 
1003  ts.tv_sec = sec + offset;
1004 
1005  /* cFYI(1, "sec after cnvrt dos to unix time %d",sec); */
1006 
1007  ts.tv_nsec = 0;
1008  return ts;
1009 }