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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * This module defines generic functions to map Native OS and Native
30  * LanMan names to values.
31  */
32 
33 #ifdef _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 /*
43  * smbnative_os_value
44  *
45  * Return the appropriate native OS value for the specified native OS name.
46  *
47  * Windows 2000 server:            "Windows 2000 2195"
48  * Windows XP Professional client: "Windows 2002 2543"
49  * Windows XP PDC server:          "Windows 5.1"
50  * Windows .Net:                   "Windows .NET 3621"
51  * Windows .Net:                   "Windows .NET 3718"
52  *
53  * DAVE (Thursby Software: CIFS for MacOS) uses "MacOS", sometimes with a
54  * version number appended, i.e. "MacOS 8.5.1". We treat DAVE like NT 4.0
55  * except for the cases that DAVE clients set 'watch tree' flag in notify
56  * change requests.
57  *
58  * Samba reports UNIX as its Native OS, which we can map to NT 4.0.
59  */
60 int
61 smbnative_os_value(char *native_os)
62 {
63 	typedef struct native_os_table {
64 		int os_value;
65 		char *os_name;
66 	} native_os_table_t;
67 
68 	static native_os_table_t os_table[] = {
69 		{ NATIVE_OS_WINNT,	"Windows NT 4.0"	},
70 		{ NATIVE_OS_WINNT,	"Windows NT"		},
71 		{ NATIVE_OS_WIN95,	"Windows 4.0"		},
72 		{ NATIVE_OS_WIN2000,	"Windows 5.0"		},
73 		{ NATIVE_OS_WIN2000,	"Windows 5.1"		},
74 		{ NATIVE_OS_WIN2000,	"Windows 2000 5.0"	},
75 		{ NATIVE_OS_NT5_1,	"Windows 2000 5.1"	},
76 		{ NATIVE_OS_WIN2000,	"Windows 2000"		},
77 		{ NATIVE_OS_WIN2000,	"Windows 2002"		},
78 		{ NATIVE_OS_WIN2000,	"Windows .NET"		},
79 		{ NATIVE_OS_WIN2000,	"Windows Server 2003"	},
80 		{ NATIVE_OS_WIN2000,	"Windows XP"		},
81 		{ NATIVE_OS_WINNT,	"UNIX"			},
82 		{ NATIVE_OS_MACOS,	"MacOS" 		}
83 	};
84 
85 	int i;
86 	int len;
87 	char *os_name;
88 
89 	if (native_os == NULL) {
90 		return (NATIVE_OS_UNKNOWN);
91 	}
92 
93 	if (*native_os == '\0') {
94 		/*
95 		 * Windows Vista sends an empty native OS string.
96 		 */
97 		return (NATIVE_OS_WIN2000);
98 	}
99 
100 	for (i = 0; i < sizeof (os_table)/sizeof (os_table[0]); ++i) {
101 		os_name = os_table[i].os_name;
102 		len = strlen(os_name);
103 
104 		if (utf8_strncasecmp(os_name, native_os, len) == 0) {
105 			return (os_table[i].os_value);
106 		}
107 	}
108 	return (NATIVE_OS_UNKNOWN);
109 }
110 
111 
112 /*
113  * smbnative_lm_value
114  *
115  * Return the appropriate native LanMan value for the specified native
116  * LanMan name. There's an alignment problem in some packets from some
117  * clients that means we can miss the first character, so we do an
118  * additional check starting from the second character.
119  *
120  * DAVE (Thursby Software: CIFS for MacOS) sometimes uses a Unicode
121  * character in the LanMan name. Variations seen so far are:
122  *
123  *	44 00 41 00 56 00 45 00 00 00        D.A.V.E...
124  *
125  *	44 00 41 00 56 00 45 00 22 21 20 00 56 00 32 00
126  *	2E 00 35 00 2E 00 31 00 00 00        D.A.V.E."!..V.2...5...1...
127  *
128  * Samba reports its own name (Samba) as its Native LM, which we can
129  * map to NT LM 4.0.
130  */
131 int
132 smbnative_lm_value(char *native_lm)
133 {
134 	typedef struct native_lm_table {
135 		int lm_value;
136 		char *lm_name;
137 	} native_lm_table_t;
138 
139 	static native_lm_table_t lm_table[] = {
140 		{ NATIVE_LM_NT,		"NT LAN Manager 4.0"		},
141 		{ NATIVE_LM_NT,		"Windows NT 4.0"		},
142 		{ NATIVE_LM_NT,		"Windows NT"			},
143 		{ NATIVE_LM_NT,		"Windows 4.0"			},
144 		{ NATIVE_LM_WIN2000,	"Windows 2000 LAN Manager"	},
145 		{ NATIVE_LM_WIN2000,	"Windows 2000 5.0"		},
146 		{ NATIVE_LM_WIN2000,	"Windows 2000 5.1"		},
147 		{ NATIVE_LM_WIN2000,	"Windows 2000",			},
148 		{ NATIVE_LM_WIN2000,	"Windows 2002 5.1"		},
149 		{ NATIVE_LM_WIN2000,	"Windows 2002"			},
150 		{ NATIVE_LM_WIN2000,	"Windows .NET 5.2"		},
151 		{ NATIVE_LM_WIN2000,	"Windows .NET"			},
152 		{ NATIVE_LM_WIN2000,	"Windows Server 2003"		},
153 		{ NATIVE_LM_WIN2000,	"Windows XP"			},
154 		{ NATIVE_LM_NT,		"Samba"				},
155 		{ NATIVE_LM_NT,		"DAVE"				}
156 	};
157 
158 	int i;
159 	int len;
160 	char *lm_name;
161 
162 	if (native_lm == NULL) {
163 		return (NATIVE_LM_NONE);
164 	}
165 
166 	if (*native_lm == '\0') {
167 		/*
168 		 * Windows Vista sends an empty native LM string.
169 		 */
170 		return (NATIVE_LM_WIN2000);
171 	}
172 
173 	for (i = 0; i < sizeof (lm_table)/sizeof (lm_table[0]); ++i) {
174 		lm_name = lm_table[i].lm_name;
175 		len = strlen(lm_name);
176 
177 		if ((utf8_strncasecmp(lm_name, native_lm, len) == 0) ||
178 		    (utf8_strncasecmp(&lm_name[1], native_lm, len - 1) == 0)) {
179 			return (lm_table[i].lm_value);
180 		}
181 	}
182 	return (NATIVE_LM_NONE);
183 }
184 
185 /*
186  * smbnative_pdc_value
187  *
188  * This function is used when NetFORCE contacting a PDC
189  * to authenticate a connected user to determine and keep
190  * the PDC type.
191  *
192  * The reason for adding this functionality is that NetFORCE
193  * doesn't support Samba PDC but code didn't check the PDC type
194  * and do authentication agains any PDC. This behaviour could
195  * cause problem in some circumstances.
196  * Now that we determine the PDC type the authentication code
197  * can be configured (by smb.samba.pdc env var) to return access
198  * denied to authentication attempts when PDC is Samba.
199  */
200 int
201 smbnative_pdc_value(char *native_lm)
202 {
203 	typedef struct pdc_table {
204 		int pdc_value;
205 		char *pdc_lmname;
206 	} pdc_table_t;
207 
208 	static pdc_table_t pdc_table[] = {
209 		{ PDC_WINNT,	"NT LAN Manager 4.0"		},
210 		{ PDC_WINNT,	"Windows NT 4.0"		},
211 		{ PDC_WINNT,	"Windows NT"			},
212 		{ PDC_WINNT,	"Windows 4.0"			},
213 		{ PDC_WIN2000,	"Windows 2000 LAN Manager"	},
214 		{ PDC_WIN2000,	"Windows 2000 5.0"		},
215 		{ PDC_WIN2000,	"Windows 2000 5.1"		},
216 		{ PDC_WIN2000,	"Windows 2000",			},
217 		{ PDC_WIN2000,	"Windows 2002 5.1"		},
218 		{ PDC_WIN2000,	"Windows 2002"			},
219 		{ PDC_WIN2000,	"Windows .NET 5.2"		},
220 		{ PDC_WIN2000,	"Windows .NET"			},
221 		{ PDC_SAMBA,	"Samba"				},
222 		{ PDC_WINNT,	"DAVE"				}
223 	};
224 
225 	int i;
226 	int len;
227 	char *pdc_lmname;
228 
229 	if (native_lm == 0) {
230 		return (PDC_UNKNOWN);
231 	}
232 
233 	for (i = 0; i < sizeof (pdc_table)/sizeof (pdc_table[0]); ++i) {
234 		pdc_lmname = pdc_table[i].pdc_lmname;
235 		len = strlen(pdc_lmname);
236 
237 		if ((utf8_strncasecmp(pdc_lmname, native_lm, len) == 0) ||
238 		    (utf8_strncasecmp(&pdc_lmname[1], native_lm, len - 1)
239 		    == 0)) {
240 			return (pdc_table[i].pdc_value);
241 		}
242 	}
243 
244 	return (PDC_UNKNOWN);
245 }
246