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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 #include <assert.h>
27 #include <sys/types.h>
28 #include <stdarg.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <time.h>
32 #include <synch.h>
33 #include <syslog.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <errno.h>
37 #include <net/if.h>
38 #include <netdb.h>
39 #include <netinet/in.h>
40 #include <arpa/nameser.h>
41 #include <resolv.h>
42 #include <sys/sockio.h>
43 #include <sys/socket.h>
44 #include <smbsrv/smbinfo.h>
45 #include <smbsrv/netbios.h>
46 #include <smbsrv/libsmb.h>
47
48 static mutex_t seqnum_mtx;
49
50 /*
51 * IPC connection information that may be passed to the SMB Redirector.
52 */
53 typedef struct {
54 char user[SMB_USERNAME_MAXLEN];
55 uint8_t passwd[SMBAUTH_HASH_SZ];
56 } smb_ipc_t;
57
58 static smb_ipc_t ipc_info;
59 static smb_ipc_t ipc_orig_info;
60 static rwlock_t smb_ipc_lock;
61
62 /*
63 * Some older clients (Windows 98) only handle the low byte
64 * of the max workers value. If the low byte is less than
65 * SMB_PI_MAX_WORKERS_MIN set it to SMB_PI_MAX_WORKERS_MIN.
66 */
67 void
smb_load_kconfig(smb_kmod_cfg_t * kcfg)68 smb_load_kconfig(smb_kmod_cfg_t *kcfg)
69 {
70 int64_t citem;
71
72 bzero(kcfg, sizeof (smb_kmod_cfg_t));
73
74 (void) smb_config_getnum(SMB_CI_MAX_WORKERS, &citem);
75 kcfg->skc_maxworkers = (uint32_t)citem;
76 if ((kcfg->skc_maxworkers & 0xFF) < SMB_PI_MAX_WORKERS_MIN) {
77 kcfg->skc_maxworkers &= ~0xFF;
78 kcfg->skc_maxworkers += SMB_PI_MAX_WORKERS_MIN;
79 }
80
81 (void) smb_config_getnum(SMB_CI_KEEPALIVE, &citem);
82 kcfg->skc_keepalive = (uint32_t)citem;
83 if ((kcfg->skc_keepalive != 0) &&
84 (kcfg->skc_keepalive < SMB_PI_KEEP_ALIVE_MIN))
85 kcfg->skc_keepalive = SMB_PI_KEEP_ALIVE_MIN;
86
87 (void) smb_config_getnum(SMB_CI_MAX_CONNECTIONS, &citem);
88 kcfg->skc_maxconnections = (uint32_t)citem;
89 kcfg->skc_restrict_anon = smb_config_getbool(SMB_CI_RESTRICT_ANON);
90 kcfg->skc_signing_enable = smb_config_getbool(SMB_CI_SIGNING_ENABLE);
91 kcfg->skc_signing_required = smb_config_getbool(SMB_CI_SIGNING_REQD);
92 kcfg->skc_netbios_enable = smb_config_getbool(SMB_CI_NETBIOS_ENABLE);
93 kcfg->skc_ipv6_enable = smb_config_getbool(SMB_CI_IPV6_ENABLE);
94 kcfg->skc_print_enable = smb_config_getbool(SMB_CI_PRINT_ENABLE);
95 kcfg->skc_oplock_enable = smb_config_getbool(SMB_CI_OPLOCK_ENABLE);
96 kcfg->skc_sync_enable = smb_config_getbool(SMB_CI_SYNC_ENABLE);
97 kcfg->skc_traverse_mounts = smb_config_getbool(SMB_CI_TRAVERSE_MOUNTS);
98 kcfg->skc_secmode = smb_config_get_secmode();
99 (void) smb_getdomainname(kcfg->skc_nbdomain,
100 sizeof (kcfg->skc_nbdomain));
101 (void) smb_getfqdomainname(kcfg->skc_fqdn,
102 sizeof (kcfg->skc_fqdn));
103 (void) smb_getnetbiosname(kcfg->skc_hostname,
104 sizeof (kcfg->skc_hostname));
105 (void) smb_config_getstr(SMB_CI_SYS_CMNT, kcfg->skc_system_comment,
106 sizeof (kcfg->skc_system_comment));
107 smb_config_get_version(&kcfg->skc_version);
108 kcfg->skc_execflags = smb_config_get_execinfo(NULL, NULL, 0);
109 }
110
111 /*
112 * Get the current system NetBIOS name. The hostname is truncated at
113 * the first `.` or 15 bytes, whichever occurs first, and converted
114 * to uppercase (by smb_gethostname). Text that appears after the
115 * first '.' is considered to be part of the NetBIOS scope.
116 *
117 * Returns 0 on success, otherwise -1 to indicate an error.
118 */
119 int
smb_getnetbiosname(char * buf,size_t buflen)120 smb_getnetbiosname(char *buf, size_t buflen)
121 {
122 if (smb_gethostname(buf, buflen, SMB_CASE_UPPER) != 0)
123 return (-1);
124
125 if (buflen >= NETBIOS_NAME_SZ)
126 buf[NETBIOS_NAME_SZ - 1] = '\0';
127
128 return (0);
129 }
130
131 /*
132 * Get the SAM account of the current system.
133 * Returns 0 on success, otherwise, -1 to indicate an error.
134 */
135 int
smb_getsamaccount(char * buf,size_t buflen)136 smb_getsamaccount(char *buf, size_t buflen)
137 {
138 if (smb_getnetbiosname(buf, buflen - 1) != 0)
139 return (-1);
140
141 (void) strlcat(buf, "$", buflen);
142 return (0);
143 }
144
145 /*
146 * Get the current system node name. The returned name is guaranteed
147 * to be null-terminated (gethostname may not null terminate the name).
148 * If the hostname has been fully-qualified for some reason, the domain
149 * part will be removed. The returned hostname is converted to the
150 * specified case (lower, upper, or preserved).
151 *
152 * If gethostname fails, the returned buffer will contain an empty
153 * string.
154 */
155 int
smb_gethostname(char * buf,size_t buflen,smb_caseconv_t which)156 smb_gethostname(char *buf, size_t buflen, smb_caseconv_t which)
157 {
158 char *p;
159
160 if (buf == NULL || buflen == 0)
161 return (-1);
162
163 if (gethostname(buf, buflen) != 0) {
164 *buf = '\0';
165 return (-1);
166 }
167
168 buf[buflen - 1] = '\0';
169
170 if ((p = strchr(buf, '.')) != NULL)
171 *p = '\0';
172
173 switch (which) {
174 case SMB_CASE_LOWER:
175 (void) smb_strlwr(buf);
176 break;
177
178 case SMB_CASE_UPPER:
179 (void) smb_strupr(buf);
180 break;
181
182 case SMB_CASE_PRESERVE:
183 default:
184 break;
185 }
186
187 return (0);
188 }
189
190 /*
191 * Obtain the fully-qualified name for this machine in lower case. If
192 * the hostname is fully-qualified, accept it. Otherwise, try to find an
193 * appropriate domain name to append to the hostname.
194 */
195 int
smb_getfqhostname(char * buf,size_t buflen)196 smb_getfqhostname(char *buf, size_t buflen)
197 {
198 char hostname[MAXHOSTNAMELEN];
199 char domain[MAXHOSTNAMELEN];
200
201 hostname[0] = '\0';
202 domain[0] = '\0';
203
204 if (smb_gethostname(hostname, MAXHOSTNAMELEN,
205 SMB_CASE_LOWER) != 0)
206 return (-1);
207
208 if (smb_getfqdomainname(domain, MAXHOSTNAMELEN) != 0)
209 return (-1);
210
211 if (hostname[0] == '\0')
212 return (-1);
213
214 if (domain[0] == '\0') {
215 (void) strlcpy(buf, hostname, buflen);
216 return (0);
217 }
218
219 (void) snprintf(buf, buflen, "%s.%s", hostname, domain);
220 return (0);
221 }
222
223 /*
224 * smb_getdomainname
225 *
226 * Returns NETBIOS name of the domain if the system is in domain
227 * mode. Or returns workgroup name if the system is in workgroup
228 * mode.
229 */
230 int
smb_getdomainname(char * buf,size_t buflen)231 smb_getdomainname(char *buf, size_t buflen)
232 {
233 int rc;
234
235 if (buf == NULL || buflen == 0)
236 return (-1);
237
238 *buf = '\0';
239 rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, buf, buflen);
240
241 if ((rc != SMBD_SMF_OK) || (*buf == '\0'))
242 return (-1);
243
244 return (0);
245 }
246
247 /*
248 * smb_getfqdomainname
249 *
250 * In the system is in domain mode, the dns_domain property value
251 * is returned. Otherwise, it returns the local domain obtained via
252 * resolver.
253 *
254 * Returns 0 upon success. Otherwise, returns -1.
255 */
256 int
smb_getfqdomainname(char * buf,size_t buflen)257 smb_getfqdomainname(char *buf, size_t buflen)
258 {
259 struct __res_state res_state;
260 int rc;
261
262 if (buf == NULL || buflen == 0)
263 return (-1);
264
265 *buf = '\0';
266 if (smb_config_get_secmode() == SMB_SECMODE_DOMAIN) {
267 rc = smb_config_getstr(SMB_CI_DOMAIN_FQDN, buf, buflen);
268
269 if ((rc != SMBD_SMF_OK) || (*buf == '\0'))
270 return (-1);
271 } else {
272 bzero(&res_state, sizeof (struct __res_state));
273 if (res_ninit(&res_state))
274 return (-1);
275
276 if (*res_state.defdname == '\0') {
277 res_ndestroy(&res_state);
278 return (-1);
279 }
280
281 (void) strlcpy(buf, res_state.defdname, buflen);
282 res_ndestroy(&res_state);
283 rc = 0;
284 }
285
286 return (rc);
287 }
288
289
290 /*
291 * smb_set_machine_passwd
292 *
293 * This function should be used when setting the machine password property.
294 * The associated sequence number is incremented.
295 */
296 static int
smb_set_machine_passwd(char * passwd)297 smb_set_machine_passwd(char *passwd)
298 {
299 int64_t num;
300 int rc = -1;
301
302 if (smb_config_set(SMB_CI_MACHINE_PASSWD, passwd) != SMBD_SMF_OK)
303 return (-1);
304
305 (void) mutex_lock(&seqnum_mtx);
306 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &num);
307 if (smb_config_setnum(SMB_CI_KPASSWD_SEQNUM, ++num)
308 == SMBD_SMF_OK)
309 rc = 0;
310 (void) mutex_unlock(&seqnum_mtx);
311 return (rc);
312 }
313
314 static int
smb_get_machine_passwd(uint8_t * buf,size_t buflen)315 smb_get_machine_passwd(uint8_t *buf, size_t buflen)
316 {
317 char pwd[SMB_PASSWD_MAXLEN + 1];
318 int rc;
319
320 if (buflen < SMBAUTH_HASH_SZ)
321 return (-1);
322
323 rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD, pwd, sizeof (pwd));
324 if ((rc != SMBD_SMF_OK) || *pwd == '\0')
325 return (-1);
326
327 if (smb_auth_ntlm_hash(pwd, buf) != 0)
328 return (-1);
329
330 return (rc);
331 }
332
333 /*
334 * Set up IPC connection credentials.
335 */
336 void
smb_ipc_init(void)337 smb_ipc_init(void)
338 {
339 int rc;
340
341 (void) rw_wrlock(&smb_ipc_lock);
342 bzero(&ipc_info, sizeof (smb_ipc_t));
343 bzero(&ipc_orig_info, sizeof (smb_ipc_t));
344
345 (void) smb_getsamaccount(ipc_info.user, SMB_USERNAME_MAXLEN);
346 rc = smb_get_machine_passwd(ipc_info.passwd, SMBAUTH_HASH_SZ);
347 if (rc != 0)
348 *ipc_info.passwd = 0;
349 (void) rw_unlock(&smb_ipc_lock);
350
351 }
352
353 /*
354 * Set the IPC username and password hash in memory. If the domain
355 * join succeeds, the credentials will be committed for use with
356 * authenticated IPC. Otherwise, they should be rolled back.
357 */
358 void
smb_ipc_set(char * plain_user,uint8_t * passwd_hash)359 smb_ipc_set(char *plain_user, uint8_t *passwd_hash)
360 {
361 (void) rw_wrlock(&smb_ipc_lock);
362 (void) strlcpy(ipc_info.user, plain_user, sizeof (ipc_info.user));
363 (void) memcpy(ipc_info.passwd, passwd_hash, SMBAUTH_HASH_SZ);
364 (void) rw_unlock(&smb_ipc_lock);
365
366 }
367
368 /*
369 * Save the host credentials to be used for authenticated IPC.
370 * The credentials are also saved to the original IPC info as
371 * rollback data in case the join domain process fails later.
372 */
373 void
smb_ipc_commit(void)374 smb_ipc_commit(void)
375 {
376 (void) rw_wrlock(&smb_ipc_lock);
377 (void) smb_getsamaccount(ipc_info.user, SMB_USERNAME_MAXLEN);
378 (void) smb_get_machine_passwd(ipc_info.passwd, SMBAUTH_HASH_SZ);
379 (void) memcpy(&ipc_orig_info, &ipc_info, sizeof (smb_ipc_t));
380 (void) rw_unlock(&smb_ipc_lock);
381 }
382
383 /*
384 * Restore the original credentials
385 */
386 void
smb_ipc_rollback(void)387 smb_ipc_rollback(void)
388 {
389 (void) rw_wrlock(&smb_ipc_lock);
390 (void) strlcpy(ipc_info.user, ipc_orig_info.user,
391 sizeof (ipc_info.user));
392 (void) memcpy(ipc_info.passwd, ipc_orig_info.passwd,
393 sizeof (ipc_info.passwd));
394 (void) rw_unlock(&smb_ipc_lock);
395 }
396
397 void
smb_ipc_get_user(char * buf,size_t buflen)398 smb_ipc_get_user(char *buf, size_t buflen)
399 {
400 (void) rw_rdlock(&smb_ipc_lock);
401 (void) strlcpy(buf, ipc_info.user, buflen);
402 (void) rw_unlock(&smb_ipc_lock);
403 }
404
405 void
smb_ipc_get_passwd(uint8_t * buf,size_t buflen)406 smb_ipc_get_passwd(uint8_t *buf, size_t buflen)
407 {
408 if (buflen < SMBAUTH_HASH_SZ)
409 return;
410
411 (void) rw_rdlock(&smb_ipc_lock);
412 (void) memcpy(buf, ipc_info.passwd, SMBAUTH_HASH_SZ);
413 (void) rw_unlock(&smb_ipc_lock);
414 }
415
416 /*
417 * smb_match_netlogon_seqnum
418 *
419 * A sequence number is associated with each machine password property
420 * update and the netlogon credential chain setup. If the
421 * sequence numbers don't match, a NETLOGON credential chain
422 * establishment is required.
423 *
424 * Returns 0 if kpasswd_seqnum equals to netlogon_seqnum. Otherwise,
425 * returns -1.
426 */
427 boolean_t
smb_match_netlogon_seqnum(void)428 smb_match_netlogon_seqnum(void)
429 {
430 int64_t setpasswd_seqnum;
431 int64_t netlogon_seqnum;
432
433 (void) mutex_lock(&seqnum_mtx);
434 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &setpasswd_seqnum);
435 (void) smb_config_getnum(SMB_CI_NETLOGON_SEQNUM, &netlogon_seqnum);
436 (void) mutex_unlock(&seqnum_mtx);
437 return (setpasswd_seqnum == netlogon_seqnum);
438 }
439
440 /*
441 * smb_setdomainprops
442 *
443 * This function should be called after joining an AD to
444 * set all the domain related SMF properties.
445 *
446 * The kpasswd_domain property is the AD domain to which the system
447 * is joined via kclient. If this function is invoked by the SMB
448 * daemon, fqdn should be set to NULL.
449 */
450 int
smb_setdomainprops(char * fqdn,char * server,char * passwd)451 smb_setdomainprops(char *fqdn, char *server, char *passwd)
452 {
453 if (server == NULL || passwd == NULL)
454 return (-1);
455
456 if ((*server == '\0') || (*passwd == '\0'))
457 return (-1);
458
459 if (fqdn && (smb_config_set(SMB_CI_KPASSWD_DOMAIN, fqdn) != 0))
460 return (-1);
461
462 if (smb_config_set(SMB_CI_KPASSWD_SRV, server) != 0)
463 return (-1);
464
465 if (smb_set_machine_passwd(passwd) != 0) {
466 syslog(LOG_ERR, "smb_setdomainprops: failed to set"
467 " machine account password");
468 return (-1);
469 }
470
471 /*
472 * If we successfully create a trust account, we mark
473 * ourselves as a domain member in the environment so
474 * that we use the SAMLOGON version of the NETLOGON
475 * PDC location protocol.
476 */
477 (void) smb_config_setbool(SMB_CI_DOMAIN_MEMB, B_TRUE);
478
479 return (0);
480 }
481
482 /*
483 * smb_update_netlogon_seqnum
484 *
485 * This function should only be called upon a successful netlogon
486 * credential chain establishment to set the sequence number of the
487 * netlogon to match with that of the kpasswd.
488 */
489 void
smb_update_netlogon_seqnum(void)490 smb_update_netlogon_seqnum(void)
491 {
492 int64_t num;
493
494 (void) mutex_lock(&seqnum_mtx);
495 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &num);
496 (void) smb_config_setnum(SMB_CI_NETLOGON_SEQNUM, num);
497 (void) mutex_unlock(&seqnum_mtx);
498 }
499
500
501 /*
502 * Temporary fbt for dtrace until user space sdt enabled.
503 */
504 void
smb_tracef(const char * fmt,...)505 smb_tracef(const char *fmt, ...)
506 {
507 va_list ap;
508 char buf[128];
509
510 va_start(ap, fmt);
511 (void) vsnprintf(buf, 128, fmt, ap);
512 va_end(ap);
513
514 smb_trace(buf);
515 }
516
517 /*
518 * Temporary fbt for dtrace until user space sdt enabled.
519 *
520 * This function is designed to be used with dtrace, i.e. see:
521 * usr/src/cmd/smbsrv/dtrace/smbd-all.d
522 *
523 * Outside of dtrace, the messages passed to this function usually
524 * lack sufficient context to be useful, so we don't log them.
525 */
526 /* ARGSUSED */
527 void
smb_trace(const char * s)528 smb_trace(const char *s)
529 {
530 }
531
532 /*
533 * smb_tonetbiosname
534 *
535 * Creates a NetBIOS name based on the given name and suffix.
536 * NetBIOS name is 15 capital characters, padded with space if needed
537 * and the 16th byte is the suffix.
538 */
539 void
smb_tonetbiosname(char * name,char * nb_name,char suffix)540 smb_tonetbiosname(char *name, char *nb_name, char suffix)
541 {
542 char tmp_name[NETBIOS_NAME_SZ];
543 smb_wchar_t wtmp_name[NETBIOS_NAME_SZ];
544 int len;
545 size_t rc;
546
547 len = 0;
548 rc = smb_mbstowcs(wtmp_name, (const char *)name, NETBIOS_NAME_SZ);
549
550 if (rc != (size_t)-1) {
551 wtmp_name[NETBIOS_NAME_SZ - 1] = 0;
552 rc = ucstooem(tmp_name, wtmp_name, NETBIOS_NAME_SZ,
553 OEM_CPG_850);
554 if (rc > 0)
555 len = strlen(tmp_name);
556 }
557
558 (void) memset(nb_name, ' ', NETBIOS_NAME_SZ - 1);
559 if (len) {
560 (void) smb_strupr(tmp_name);
561 (void) memcpy(nb_name, tmp_name, len);
562 }
563 nb_name[NETBIOS_NAME_SZ - 1] = suffix;
564 }
565
566 int
smb_get_nameservers(smb_inaddr_t * ips,int sz)567 smb_get_nameservers(smb_inaddr_t *ips, int sz)
568 {
569 union res_sockaddr_union set[MAXNS];
570 int i, cnt;
571 struct __res_state res_state;
572 char ipstr[INET6_ADDRSTRLEN];
573
574 if (ips == NULL)
575 return (0);
576
577 bzero(&res_state, sizeof (struct __res_state));
578 if (res_ninit(&res_state) < 0)
579 return (0);
580
581 cnt = res_getservers(&res_state, set, MAXNS);
582 for (i = 0; i < cnt; i++) {
583 if (i >= sz)
584 break;
585 ips[i].a_family = AF_INET;
586 bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv4, NS_INADDRSZ);
587 if (inet_ntop(AF_INET, &ips[i].a_ipv4, ipstr,
588 INET_ADDRSTRLEN)) {
589 syslog(LOG_DEBUG, "Found %s name server\n", ipstr);
590 continue;
591 }
592 ips[i].a_family = AF_INET6;
593 bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv6, NS_IN6ADDRSZ);
594 if (inet_ntop(AF_INET6, &ips[i].a_ipv6, ipstr,
595 INET6_ADDRSTRLEN)) {
596 syslog(LOG_DEBUG, "Found %s name server\n", ipstr);
597 }
598 }
599 res_ndestroy(&res_state);
600 return (i);
601 }
602
603 /*
604 * smb_gethostbyname
605 *
606 * Looks up a host by the given name. The host entry can come
607 * from any of the sources for hosts specified in the
608 * /etc/nsswitch.conf and the NetBIOS cache.
609 *
610 * XXX Invokes nbt_name_resolve API once the NBTD is integrated
611 * to look in the NetBIOS cache if getipnodebyname fails.
612 *
613 * Caller should invoke freehostent to free the returned hostent.
614 */
615 struct hostent *
smb_gethostbyname(const char * name,int * err_num)616 smb_gethostbyname(const char *name, int *err_num)
617 {
618 struct hostent *h;
619
620 h = getipnodebyname(name, AF_INET, 0, err_num);
621 if ((h == NULL) || h->h_length != INADDRSZ)
622 h = getipnodebyname(name, AF_INET6, AI_DEFAULT, err_num);
623 return (h);
624 }
625
626 /*
627 * smb_gethostbyaddr
628 *
629 * Looks up a host by the given IP address. The host entry can come
630 * from any of the sources for hosts specified in the
631 * /etc/nsswitch.conf and the NetBIOS cache.
632 *
633 * XXX Invokes nbt API to resolve name by IP once the NBTD is integrated
634 * to look in the NetBIOS cache if getipnodebyaddr fails.
635 *
636 * Caller should invoke freehostent to free the returned hostent.
637 */
638 struct hostent *
smb_gethostbyaddr(const char * addr,int len,int type,int * err_num)639 smb_gethostbyaddr(const char *addr, int len, int type, int *err_num)
640 {
641 struct hostent *h;
642
643 h = getipnodebyaddr(addr, len, type, err_num);
644
645 return (h);
646 }
647