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 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2019 Nexenta Systems, Inc.  All rights reserved.
25  */
26 
27 /*
28  * LSA lookups
29  */
30 
31 #include <stdio.h>
32 #include <note.h>
33 #include <assert.h>
34 
35 #include "idmapd.h"
36 #include "libsmb.h"
37 
38 idmap_retcode
39 idmap_lsa_xlate_sid_type(const lsa_account_t *acct, idmap_id_type *ret_type)
40 {
41 	switch (acct->a_sidtype) {
42 	case SidTypeUser:
43 	case SidTypeComputer:
44 	case SidTypeDomain:
45 	case SidTypeDeletedAccount:
46 	case SidTypeUnknown:
47 	case SidTypeLabel:
48 		*ret_type = IDMAP_USID;
49 		return (IDMAP_SUCCESS);
50 	case SidTypeGroup:
51 	case SidTypeAlias:
52 	case SidTypeWellKnownGroup:
53 		*ret_type = IDMAP_GSID;
54 		return (IDMAP_SUCCESS);
55 	case SidTypeNull:
56 	case SidTypeInvalid:
57 	default:
58 		idmapdlog(LOG_WARNING,
59 		    "LSA lookup:  bad type %d for %s@%s",
60 		    acct->a_sidtype, acct->a_name, acct->a_domain);
61 		return (IDMAP_ERR_OTHER);
62 	}
63 	NOTE(NOTREACHED)
64 }
65 
66 /* Given SID, look up name and type */
67 idmap_retcode
68 lookup_lsa_by_sid(
69     const char *sidprefix,
70     uint32_t rid,
71     char **ret_name,
72     char **ret_domain,
73     idmap_id_type *ret_type)
74 {
75 	lsa_account_t acct;
76 	char sid[SMB_SID_STRSZ + 1];
77 	idmap_retcode ret;
78 	int rc;
79 
80 	(void) memset(&acct, 0, sizeof (acct));
81 	*ret_name = NULL;
82 	*ret_domain = NULL;
83 
84 	(void) snprintf(sid, sizeof (sid), "%s-%u", sidprefix, rid);
85 
86 	rc = smb_lookup_lsid(sid, &acct);
87 	if (rc != 0) {
88 		idmapdlog(LOG_ERR, "Error: SMB lookup SID failed.");
89 		idmapdlog(LOG_ERR,
90 		    "Check SMB service (svc:/network/smb/server).");
91 		idmapdlog(LOG_ERR,
92 		    "Check connectivity to Active Directory.");
93 
94 		ret = IDMAP_ERR_OTHER;
95 		goto out;
96 	}
97 	if (acct.a_status == NT_STATUS_NONE_MAPPED) {
98 		ret = IDMAP_ERR_NOTFOUND;
99 		goto out;
100 	}
101 	if (acct.a_status != NT_STATUS_SUCCESS) {
102 		idmapdlog(LOG_WARNING,
103 		    "Warning:  SMB lookup SID(%s) failed (0x%x)",
104 		    sid, acct.a_status);
105 		/* Fail soft */
106 		ret = IDMAP_ERR_NOTFOUND;
107 		goto out;
108 	}
109 
110 	ret = idmap_lsa_xlate_sid_type(&acct, ret_type);
111 	if (ret != IDMAP_SUCCESS)
112 		goto out;
113 
114 	*ret_name = strdup(acct.a_name);
115 	if (*ret_name == NULL) {
116 		ret = IDMAP_ERR_MEMORY;
117 		goto out;
118 	}
119 
120 	*ret_domain = strdup(acct.a_domain);
121 	if (*ret_domain == NULL) {
122 		ret = IDMAP_ERR_MEMORY;
123 		goto out;
124 	}
125 
126 	ret = IDMAP_SUCCESS;
127 
128 out:
129 	if (ret != IDMAP_SUCCESS) {
130 		free(*ret_name);
131 		*ret_name = NULL;
132 		free(*ret_domain);
133 		*ret_domain = NULL;
134 	}
135 	return (ret);
136 }
137 
138 /* Given name and optional domain, look up SID, type, and canonical name */
139 idmap_retcode
140 lookup_lsa_by_name(
141     const char *name,
142     const char *domain,
143     char **ret_sidprefix,
144     uint32_t *ret_rid,
145     char **ret_name,
146     char **ret_domain,
147     idmap_id_type *ret_type)
148 {
149 	lsa_account_t acct;
150 	char *namedom = NULL;
151 	idmap_retcode ret;
152 	int rc;
153 
154 	(void) memset(&acct, 0, sizeof (acct));
155 	*ret_sidprefix = NULL;
156 	if (ret_name != NULL)
157 		*ret_name = NULL;
158 	if (ret_domain != NULL)
159 		*ret_domain = NULL;
160 
161 	if (domain != NULL)
162 		(void) asprintf(&namedom, "%s@%s", name, domain);
163 	else
164 		namedom = strdup(name);
165 	if (namedom == NULL) {
166 		ret = IDMAP_ERR_MEMORY;
167 		goto out;
168 	}
169 
170 	rc = smb_lookup_lname(namedom, SidTypeUnknown, &acct);
171 	if (rc != 0) {
172 		idmapdlog(LOG_ERR, "Error: SMB lookup name failed.");
173 		idmapdlog(LOG_ERR,
174 		    "Check SMB service (svc:/network/smb/server).");
175 		idmapdlog(LOG_ERR,
176 		    "Check connectivity to Active Directory.");
177 		ret = IDMAP_ERR_OTHER;
178 		goto out;
179 	}
180 	if (acct.a_status == NT_STATUS_NONE_MAPPED) {
181 		ret = IDMAP_ERR_NOTFOUND;
182 		goto out;
183 	}
184 	if (acct.a_status != NT_STATUS_SUCCESS) {
185 		idmapdlog(LOG_WARNING,
186 		    "Warning: SMB lookup name(%s) failed (0x%x)",
187 		    namedom, acct.a_status);
188 		/* Fail soft */
189 		ret = IDMAP_ERR_NOTFOUND;
190 		goto out;
191 	}
192 
193 	rc = smb_sid_splitstr(acct.a_sid, ret_rid);
194 	assert(rc == 0);
195 	*ret_sidprefix = strdup(acct.a_sid);
196 	if (*ret_sidprefix == NULL) {
197 		ret = IDMAP_ERR_MEMORY;
198 		goto out;
199 	}
200 
201 	ret = idmap_lsa_xlate_sid_type(&acct, ret_type);
202 	if (ret != IDMAP_SUCCESS)
203 		goto out;
204 
205 	if (ret_name != NULL) {
206 		*ret_name = strdup(acct.a_name);
207 		if (*ret_name == NULL) {
208 			ret = IDMAP_ERR_MEMORY;
209 			goto out;
210 		}
211 	}
212 
213 	if (ret_domain != NULL) {
214 		*ret_domain = strdup(acct.a_domain);
215 		if (*ret_domain == NULL) {
216 			ret = IDMAP_ERR_MEMORY;
217 			goto out;
218 		}
219 	}
220 
221 	ret = IDMAP_SUCCESS;
222 
223 out:
224 	free(namedom);
225 	if (ret != IDMAP_SUCCESS) {
226 		if (ret_name != NULL) {
227 			free(*ret_name);
228 			*ret_name = NULL;
229 		}
230 		if (ret_domain != NULL) {
231 			free(*ret_domain);
232 			*ret_domain = NULL;
233 		}
234 		free(*ret_sidprefix);
235 		*ret_sidprefix = NULL;
236 	}
237 	return (ret);
238 }
239 
240 /*
241  * This exists just so we can avoid exposing all of idmapd to libsmb.h.
242  * Like the above functions, it's a door call over to smbd.
243  */
244 void
245 notify_dc_changed(void)
246 {
247 	smb_notify_dc_changed();
248 }
249