xref: /illumos-gate/usr/src/common/smbsrv/smb_native.c (revision 9b9d39d2a32ff806d2431dbcc50968ef1e6d46b2)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
26  */
27 
28 /*
29  * This module defines generic functions to map Native OS and Native
30  * LanMan names to values.
31  */
32 
33 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
34 #include <sys/types.h>
35 #include <sys/sunddi.h>
36 #else
37 #include <string.h>
38 #endif
39 #include <smbsrv/string.h>
40 #include <smbsrv/smbinfo.h>
41 
42 typedef struct smb_native {
43 	int sn_value;
44 	const char *sn_name;
45 } smb_native_t;
46 
47 /*
48  * smbnative_os_value
49  *
50  * Return the appropriate native OS value for the specified native OS name.
51  *
52  * Example OS values used by Windows:
53  *
54  *	Windows 4.0, Windows NT, Windows NT 4.0
55  *	Windows 5.0, Windows 5.1
56  *	Windows 2000, Windows 2000 5.0, Windows 2000 5.1
57  *	Windows 2002
58  *	Windows .NET
59  *	Windows Server 2003
60  *	Windows XP
61  *
62  * Windows 2000 server:            "Windows 2000 2195"
63  * Windows XP Professional client: "Windows 2002 2543"
64  * Windows XP PDC server:          "Windows 5.1"
65  * Windows .Net:                   "Windows .NET 3621"
66  * Windows .Net:                   "Windows .NET 3718"
67  *
68  * DAVE (Thursby Software: CIFS for MacOS) uses "MacOS", sometimes with a
69  * version number appended, i.e. "MacOS 8.5.1". We treat DAVE like NT 4.0
70  * except for the cases that DAVE clients set 'watch tree' flag in notify
71  * change requests.
72  *
73  * Samba reports UNIX as its Native OS, which we can map to NT 4.0.
74  */
75 int
76 smbnative_os_value(const char *native_os)
77 {
78 	static smb_native_t os_table[] = {
79 		{ NATIVE_OS_WINNT,	"Windows NT 4.0"	},
80 		{ NATIVE_OS_WINNT,	"Windows NT"		},
81 		{ NATIVE_OS_WIN95,	"Windows 4.0"		},
82 		{ NATIVE_OS_WIN2000,	"Windows 5.0"		},
83 		{ NATIVE_OS_WIN2000,	"Windows 5.1"		},
84 		{ NATIVE_OS_WIN2000,	"Windows 2000"		},
85 		{ NATIVE_OS_WIN2000,	"Windows 2002"		},
86 		{ NATIVE_OS_WIN2000,	"Windows .NET"		},
87 		{ NATIVE_OS_WIN2000,	"Windows Server"	},
88 		{ NATIVE_OS_WIN2000,	"Windows XP"		},
89 		{ NATIVE_OS_WINNT,	"UNIX"			},
90 		{ NATIVE_OS_MACOS,	"MacOS" 		}
91 	};
92 
93 	int i;
94 	int len;
95 	const char *name;
96 
97 	if (native_os == NULL)
98 		return (NATIVE_OS_UNKNOWN);
99 
100 	/*
101 	 * Windows Vista sends an empty native OS string.
102 	 */
103 	if (*native_os == '\0')
104 		return (NATIVE_OS_WIN2000);
105 
106 	for (i = 0; i < sizeof (os_table)/sizeof (os_table[0]); ++i) {
107 		name = os_table[i].sn_name;
108 		len = strlen(name);
109 
110 		if (smb_strcasecmp(name, native_os, len) == 0)
111 			return (os_table[i].sn_value);
112 	}
113 
114 	return (NATIVE_OS_UNKNOWN);
115 }
116 
117 /*
118  * smbnative_lm_value
119  *
120  * Return the appropriate native LanMan value for the specified native
121  * LanMan name. There's an alignment problem in some packets from some
122  * clients that means we can miss the first character, so we do an
123  * additional check starting from the second character.
124  *
125  * Example LanMan values:
126  *
127  *	NT LAN Manager 4.0
128  *	Windows 4.0
129  *	Windows NT, Windows NT 4.0
130  *	Windows 2000 LAN Manager
131  *	Windows 2000, Windows 2000 5.0, Windows 2000 5.1
132  *	Windows 2002, Windows 2002 5.1
133  *	Windows .NET, Windows .NET 5.2
134  *	Windows Server 2003
135  *	Windows XP
136  *	NETSMB		(Solaris CIFS client)
137  *	DAVE		(Thursby Software: CIFS for MacOS)
138  *	Samba
139  */
140 int
141 smbnative_lm_value(const char *native_lm)
142 {
143 	static smb_native_t lm_table[] = {
144 		{ NATIVE_LM_NT,		"NT LAN Manager 4.0"		},
145 		{ NATIVE_LM_NT,		"Windows NT"			},
146 		{ NATIVE_LM_NT,		"Windows 4.0"			},
147 		{ NATIVE_LM_NT,		"DAVE"				}
148 	};
149 
150 	int i;
151 	int len;
152 	const char *name;
153 
154 	/*
155 	 * Windows Vista sends an empty native LM string.
156 	 */
157 	if (native_lm == NULL || *native_lm == '\0')
158 		return (NATIVE_LM_WIN2000);
159 
160 	for (i = 0; i < sizeof (lm_table)/sizeof (lm_table[0]); ++i) {
161 		name = lm_table[i].sn_name;
162 		len = strlen(name);
163 
164 		if ((smb_strcasecmp(name, native_lm, len) == 0) ||
165 		    (smb_strcasecmp(&name[1], native_lm, len - 1) == 0)) {
166 			return (lm_table[i].sn_value);
167 		}
168 	}
169 
170 	return (NATIVE_LM_WIN2000);
171 }
172 
173 /*
174  * smbnative_pdc_value
175  *
176  * This function is called when libsmbrdr connects to a PDC.
177  * The PDC type is derived from the Native LanMan string.
178  * The PDC value will default to PDC_WIN2000.
179  *
180  * Example strings:
181  *
182  *	NT LAN Manager 4.0
183  *	Windows 4.0, Windows NT, Windows NT 4.0
184  *	Windows 2000 LAN Manager
185  *	Windows 2000, Windows 2000 5.0, Windows 2000 5.1
186  *	Windows 2002, Windows 2002 5.1
187  *	Windows .NET, Windows .NET 5.2
188  *	Samba
189  *	DAVE
190  */
191 int
192 smbnative_pdc_value(const char *native_lm)
193 {
194 	static smb_native_t pdc_table[] = {
195 		{ PDC_WINNT,	"NT LAN Manager 4.0"		},
196 		{ PDC_WINNT,	"Windows NT 4.0"		},
197 		{ PDC_WINNT,	"Windows NT"			},
198 		{ PDC_WINNT,	"Windows 4.0"			},
199 		{ PDC_WINNT,	"DAVE"				},
200 		{ PDC_SAMBA,	"Samba"				}
201 	};
202 
203 	int i;
204 	int len;
205 	const char *name;
206 
207 	if (native_lm == NULL || *native_lm == '\0')
208 		return (PDC_WIN2000);
209 
210 	for (i = 0; i < sizeof (pdc_table)/sizeof (pdc_table[0]); ++i) {
211 		name = pdc_table[i].sn_name;
212 		len = strlen(name);
213 
214 		if ((smb_strcasecmp(name, native_lm, len) == 0) ||
215 		    (smb_strcasecmp(&name[1], native_lm, len - 1) == 0)) {
216 			return (pdc_table[i].sn_value);
217 		}
218 	}
219 
220 	return (PDC_WIN2000);
221 }
222 
223 /*
224  * Returns the native OS string for the given OS version.
225  * If no match is found the string for Windows 2000 is returned.
226  */
227 const char *
228 smbnative_os_str(smb_version_t *version)
229 {
230 	int i;
231 
232 	static smb_native_t osstr_table[] = {
233 		{ SMB_MAJOR_NT,		"Windows NT"		},
234 		{ SMB_MAJOR_2000,	"Windows 2000"		},
235 		{ SMB_MAJOR_XP,		"Windows XP"		},
236 		{ SMB_MAJOR_2003,	"Windows Server 2003"	},
237 		{ SMB_MAJOR_VISTA,	""			},
238 		{ SMB_MAJOR_2008,	""			},
239 		{ SMB_MAJOR_2008R2,	""			}
240 	};
241 
242 	for (i = 0; i < sizeof (osstr_table)/sizeof (osstr_table[0]); ++i) {
243 		if (version->sv_major == osstr_table[i].sn_value)
244 			return (osstr_table[i].sn_name);
245 	}
246 
247 	return (osstr_table[1].sn_name);
248 }
249 
250 /*
251  * Returns the native Lanman string for the given OS version.
252  * If no match is found the string for Windows 2000 is returned.
253  */
254 const char *
255 smbnative_lm_str(smb_version_t *version)
256 {
257 	int i;
258 
259 	static smb_native_t lmstr_table[] = {
260 		{ SMB_MAJOR_NT,		"NT LAN Manager 4.0"		},
261 		{ SMB_MAJOR_2000,	"Windows 2000 LAN Manager"	},
262 		{ SMB_MAJOR_XP,		"Windows 2002 5.1"		},
263 		{ SMB_MAJOR_2003,	"Windows Server 2003 5.2"	},
264 		{ SMB_MAJOR_VISTA,	""				},
265 		{ SMB_MAJOR_2008,	""				},
266 		{ SMB_MAJOR_2008R2,	""				}
267 	};
268 
269 	for (i = 0; i < sizeof (lmstr_table)/sizeof (lmstr_table[0]); ++i) {
270 		if (version->sv_major == lmstr_table[i].sn_value)
271 			return (lmstr_table[i].sn_name);
272 	}
273 
274 	return (lmstr_table[1].sn_name);
275 }
276