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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Utility functions to support the RPC interface library.
28  */
29 
30 #include <stdio.h>
31 #include <stdarg.h>
32 #include <strings.h>
33 #include <unistd.h>
34 #include <netdb.h>
35 #include <stdlib.h>
36 #include <sys/time.h>
37 #include <sys/systm.h>
38 #include <syslog.h>
39 
40 #include <smbsrv/libsmb.h>
41 #include <smbsrv/libsmbns.h>
42 #include <smbsrv/libmlsvc.h>
43 #include <smbsrv/libsmbrdr.h>
44 #include <smbsrv/smbinfo.h>
45 #include <lsalib.h>
46 #include <samlib.h>
47 #include <smbsrv/netrauth.h>
48 
49 /* Domain join support (using MS-RPC) */
50 static boolean_t mlsvc_ntjoin_support = B_FALSE;
51 
52 extern int netr_open(char *, char *, mlsvc_handle_t *);
53 extern int netr_close(mlsvc_handle_t *);
54 extern DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD);
55 
56 /*
57  * mlsvc_lookup_name
58  *
59  * This is just a wrapper for lsa_lookup_name.
60  *
61  * The memory for the sid is allocated using malloc so the caller should
62  * call free when it is no longer required.
63  */
64 uint32_t
65 mlsvc_lookup_name(char *name, smb_sid_t **sid, uint16_t *sid_type)
66 {
67 	smb_account_t account;
68 	uint32_t status;
69 
70 	status = lsa_lookup_name(name, *sid_type, &account);
71 	if (status == NT_STATUS_SUCCESS) {
72 		*sid = account.a_sid;
73 		account.a_sid = NULL;
74 		*sid_type = account.a_type;
75 		smb_account_free(&account);
76 	}
77 
78 	return (status);
79 }
80 
81 /*
82  * mlsvc_lookup_sid
83  *
84  * This is just a wrapper for lsa_lookup_sid.
85  *
86  * The allocated memory for the returned name must be freed by caller upon
87  * successful return.
88  */
89 uint32_t
90 mlsvc_lookup_sid(smb_sid_t *sid, char **name)
91 {
92 	smb_account_t ainfo;
93 	uint32_t status;
94 	int namelen;
95 
96 	if ((status = lsa_lookup_sid(sid, &ainfo)) == NT_STATUS_SUCCESS) {
97 		namelen = strlen(ainfo.a_domain) + strlen(ainfo.a_name) + 2;
98 		if ((*name = malloc(namelen)) != NULL)
99 			(void) snprintf(*name, namelen, "%s\\%s",
100 			    ainfo.a_domain, ainfo.a_name);
101 		else
102 			status = NT_STATUS_NO_MEMORY;
103 
104 		smb_account_free(&ainfo);
105 	}
106 
107 	return (status);
108 }
109 
110 DWORD
111 mlsvc_netlogon(char *server, char *domain)
112 {
113 	mlsvc_handle_t netr_handle;
114 	DWORD status;
115 
116 	if (netr_open(server, domain, &netr_handle) == 0) {
117 		if ((status = netlogon_auth(server, &netr_handle,
118 		    NETR_FLG_INIT)) != NT_STATUS_SUCCESS)
119 			syslog(LOG_NOTICE, "Failed to establish NETLOGON "
120 			    "credential chain");
121 		(void) netr_close(&netr_handle);
122 	} else {
123 		status = NT_STATUS_OPEN_FAILED;
124 	}
125 
126 	return (status);
127 }
128 
129 /*
130  * Joins the specified domain by creating a machine account on
131  * the selected domain controller.
132  *
133  * Disconnect any existing connection with the domain controller.
134  * This will ensure that no stale connection will be used, it will
135  * also pickup any configuration changes in either side by trying
136  * to establish a new connection.
137  *
138  * Returns NT status codes.
139  */
140 DWORD
141 mlsvc_join(smb_domainex_t *dxi, char *user, char *plain_text)
142 {
143 	int erc;
144 	DWORD status;
145 	char machine_passwd[NETR_MACHINE_ACCT_PASSWD_MAX];
146 	smb_adjoin_status_t err;
147 	smb_domain_t *domain;
148 
149 	machine_passwd[0] = '\0';
150 
151 	domain = &dxi->d_primary;
152 
153 	mlsvc_disconnect(dxi->d_dc);
154 
155 	erc = smbrdr_logon(dxi->d_dc, domain->di_nbname, user);
156 
157 	if (erc == AUTH_USER_GRANT) {
158 		if (mlsvc_ntjoin_support == B_FALSE) {
159 
160 			if ((err = smb_ads_join(domain->di_fqname, user,
161 			    plain_text, machine_passwd,
162 			    sizeof (machine_passwd))) == SMB_ADJOIN_SUCCESS) {
163 				status = NT_STATUS_SUCCESS;
164 			} else {
165 				smb_ads_join_errmsg(err);
166 				status = NT_STATUS_UNSUCCESSFUL;
167 			}
168 		} else {
169 
170 			status = sam_create_trust_account(dxi->d_dc,
171 			    domain->di_nbname);
172 			if (status == NT_STATUS_SUCCESS) {
173 				(void) smb_getnetbiosname(machine_passwd,
174 				    sizeof (machine_passwd));
175 				(void) smb_strlwr(machine_passwd);
176 			}
177 		}
178 
179 		if (status == NT_STATUS_SUCCESS) {
180 			erc = smb_setdomainprops(NULL, dxi->d_dc,
181 			    machine_passwd);
182 			if (erc != 0) {
183 				syslog(LOG_NOTICE, "Failed to update CIFS "
184 				    "configuration");
185 				return (NT_STATUS_UNSUCCESSFUL);
186 			}
187 
188 			status = mlsvc_netlogon(dxi->d_dc, domain->di_nbname);
189 		}
190 	} else {
191 		status = NT_STATUS_LOGON_FAILURE;
192 	}
193 
194 	return (status);
195 }
196 
197 int
198 mlsvc_ping(const char *server)
199 {
200 	return (smbrdr_echo(server));
201 }
202 
203 void
204 mlsvc_disconnect(const char *server)
205 {
206 	smbrdr_disconnect(server);
207 }
208