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