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) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * This module provides the high level interface to the LSA RPC functions.
28 */
29
30 #include <strings.h>
31 #include <unistd.h>
32
33 #include <smbsrv/libsmb.h>
34 #include <smbsrv/libmlsvc.h>
35 #include <smbsrv/smbinfo.h>
36 #include <smbsrv/smb_token.h>
37
38 #include <lsalib.h>
39
40 static uint32_t lsa_lookup_name_builtin(char *, char *, smb_account_t *);
41 static uint32_t lsa_lookup_name_domain(char *, smb_account_t *);
42
43 static uint32_t lsa_lookup_sid_builtin(smb_sid_t *, smb_account_t *);
44 static uint32_t lsa_lookup_sid_domain(smb_sid_t *, smb_account_t *);
45
46 static int lsa_list_accounts(mlsvc_handle_t *);
47
48 /*
49 * Lookup the given account and returns the account information
50 * in the passed smb_account_t structure.
51 *
52 * The lookup is performed in the following order:
53 * well known accounts
54 * local accounts
55 * domain accounts
56 *
57 * If it's established the given account is well know or local
58 * but the lookup fails for some reason, the next step(s) won't be
59 * performed.
60 *
61 * If the name is a domain account, it may refer to a user, group or
62 * alias. If it is a local account, its type should be specified
63 * in the sid_type parameter. In case the account type is unknown
64 * sid_type should be set to SidTypeUnknown.
65 *
66 * account argument could be either [domain\]name or [domain/]name.
67 *
68 * Return status:
69 *
70 * NT_STATUS_SUCCESS Account is successfully translated
71 * NT_STATUS_NONE_MAPPED Couldn't translate the account
72 */
73 uint32_t
lsa_lookup_name(char * account,uint16_t type,smb_account_t * info)74 lsa_lookup_name(char *account, uint16_t type, smb_account_t *info)
75 {
76 char nambuf[SMB_USERNAME_MAXLEN];
77 char dombuf[SMB_PI_MAX_DOMAIN];
78 char *name, *domain;
79 uint32_t status;
80 char *slash;
81
82 (void) strsubst(account, '/', '\\');
83 (void) strcanon(account, "\\");
84 /* \john -> john */
85 account += strspn(account, "\\");
86
87 if ((slash = strchr(account, '\\')) != NULL) {
88 *slash = '\0';
89 (void) strlcpy(dombuf, account, sizeof (dombuf));
90 (void) strlcpy(nambuf, slash + 1, sizeof (nambuf));
91 *slash = '\\';
92 name = nambuf;
93 domain = dombuf;
94 } else {
95 name = account;
96 domain = NULL;
97 }
98
99 status = lsa_lookup_name_builtin(domain, name, info);
100 if (status == NT_STATUS_NOT_FOUND) {
101 status = smb_sam_lookup_name(domain, name, type, info);
102 if (status == NT_STATUS_SUCCESS)
103 return (status);
104
105 if ((domain == NULL) || (status == NT_STATUS_NOT_FOUND))
106 status = lsa_lookup_name_domain(account, info);
107 }
108
109 return ((status == NT_STATUS_SUCCESS) ? status : NT_STATUS_NONE_MAPPED);
110 }
111
112 uint32_t
lsa_lookup_sid(smb_sid_t * sid,smb_account_t * info)113 lsa_lookup_sid(smb_sid_t *sid, smb_account_t *info)
114 {
115 uint32_t status;
116
117 if (!smb_sid_isvalid(sid))
118 return (NT_STATUS_INVALID_SID);
119
120 status = lsa_lookup_sid_builtin(sid, info);
121 if (status == NT_STATUS_NOT_FOUND) {
122 status = smb_sam_lookup_sid(sid, info);
123 if (status == NT_STATUS_NOT_FOUND)
124 status = lsa_lookup_sid_domain(sid, info);
125 }
126
127 return ((status == NT_STATUS_SUCCESS) ? status : NT_STATUS_NONE_MAPPED);
128 }
129
130 /*
131 * Obtains the primary domain SID and name from the specified server
132 * (domain controller).
133 *
134 * The requested information will be returned via 'info' argument.
135 *
136 * Returns NT status codes.
137 */
138 DWORD
lsa_query_primary_domain_info(char * server,char * domain,smb_domain_t * info)139 lsa_query_primary_domain_info(char *server, char *domain,
140 smb_domain_t *info)
141 {
142 mlsvc_handle_t domain_handle;
143 DWORD status;
144 char user[SMB_USERNAME_MAXLEN];
145
146 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
147
148 if ((lsar_open(server, domain, user, &domain_handle)) != 0)
149 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
150
151 status = lsar_query_info_policy(&domain_handle,
152 MSLSA_POLICY_PRIMARY_DOMAIN_INFO, info);
153
154 (void) lsar_close(&domain_handle);
155 return (status);
156 }
157
158 /*
159 * Obtains the account domain SID and name from the current server
160 * (domain controller).
161 *
162 * The requested information will be returned via 'info' argument.
163 *
164 * Returns NT status codes.
165 */
166 DWORD
lsa_query_account_domain_info(char * server,char * domain,smb_domain_t * info)167 lsa_query_account_domain_info(char *server, char *domain,
168 smb_domain_t *info)
169 {
170 mlsvc_handle_t domain_handle;
171 DWORD status;
172 char user[SMB_USERNAME_MAXLEN];
173
174 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
175
176 if ((lsar_open(server, domain, user, &domain_handle)) != 0)
177 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
178
179 status = lsar_query_info_policy(&domain_handle,
180 MSLSA_POLICY_ACCOUNT_DOMAIN_INFO, info);
181
182 (void) lsar_close(&domain_handle);
183 return (status);
184 }
185
186 /*
187 * lsa_query_dns_domain_info
188 *
189 * Obtains the DNS domain info from the specified server
190 * (domain controller).
191 *
192 * The requested information will be returned via 'info' argument.
193 *
194 * Returns NT status codes.
195 */
196 DWORD
lsa_query_dns_domain_info(char * server,char * domain,smb_domain_t * info)197 lsa_query_dns_domain_info(char *server, char *domain, smb_domain_t *info)
198 {
199 mlsvc_handle_t domain_handle;
200 DWORD status;
201 char user[SMB_USERNAME_MAXLEN];
202
203 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
204
205 if ((lsar_open(server, domain, user, &domain_handle)) != 0)
206 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
207
208 status = lsar_query_info_policy(&domain_handle,
209 MSLSA_POLICY_DNS_DOMAIN_INFO, info);
210
211 (void) lsar_close(&domain_handle);
212 return (status);
213 }
214
215 /*
216 * Enumerate the trusted domains of primary domain.
217 * This is the basic enumaration call which only returns the
218 * NetBIOS name of the domain and its SID.
219 *
220 * The requested information will be returned via 'info' argument.
221 *
222 * Returns NT status codes.
223 */
224 DWORD
lsa_enum_trusted_domains(char * server,char * domain,smb_trusted_domains_t * info)225 lsa_enum_trusted_domains(char *server, char *domain,
226 smb_trusted_domains_t *info)
227 {
228 mlsvc_handle_t domain_handle;
229 DWORD enum_context;
230 DWORD status;
231 char user[SMB_USERNAME_MAXLEN];
232
233 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
234
235 if ((lsar_open(server, domain, user, &domain_handle)) != 0)
236 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
237
238 enum_context = 0;
239
240 status = lsar_enum_trusted_domains(&domain_handle, &enum_context, info);
241 if (status == NT_STATUS_NO_MORE_ENTRIES) {
242 /*
243 * STATUS_NO_MORE_ENTRIES indicates that we
244 * have all of the available information.
245 */
246 status = NT_STATUS_SUCCESS;
247 }
248
249 (void) lsar_close(&domain_handle);
250 return (status);
251 }
252
253 /*
254 * Enumerate the trusted domains of the primary domain.
255 * This is the extended enumaration call which besides
256 * NetBIOS name of the domain and its SID, it will return
257 * the FQDN plus some trust information which is not used.
258 *
259 * The requested information will be returned via 'info' argument.
260 *
261 * Returns NT status codes.
262 */
263 DWORD
lsa_enum_trusted_domains_ex(char * server,char * domain,smb_trusted_domains_t * info)264 lsa_enum_trusted_domains_ex(char *server, char *domain,
265 smb_trusted_domains_t *info)
266 {
267 mlsvc_handle_t domain_handle;
268 DWORD enum_context;
269 DWORD status;
270 char user[SMB_USERNAME_MAXLEN];
271
272 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
273
274 if ((lsar_open(server, domain, user, &domain_handle)) != 0)
275 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
276
277 enum_context = 0;
278
279 status = lsar_enum_trusted_domains_ex(&domain_handle, &enum_context,
280 info);
281 if (status == NT_STATUS_NO_MORE_ENTRIES) {
282 /*
283 * STATUS_NO_MORE_ENTRIES indicates that we
284 * have all of the available information.
285 */
286 status = NT_STATUS_SUCCESS;
287 }
288
289 (void) lsar_close(&domain_handle);
290 return (status);
291 }
292
293 /*
294 * Lookup well known accounts table
295 *
296 * Return status:
297 *
298 * NT_STATUS_SUCCESS Account is translated successfully
299 * NT_STATUS_NOT_FOUND This is not a well known account
300 * NT_STATUS_NONE_MAPPED Account is found but domains don't match
301 * NT_STATUS_NO_MEMORY Memory shortage
302 * NT_STATUS_INTERNAL_ERROR Internal error/unexpected failure
303 */
304 static uint32_t
lsa_lookup_name_builtin(char * domain,char * name,smb_account_t * info)305 lsa_lookup_name_builtin(char *domain, char *name, smb_account_t *info)
306 {
307 smb_wka_t *wka;
308 char *wkadom;
309
310 bzero(info, sizeof (smb_account_t));
311
312 if ((wka = smb_wka_lookup_name(name)) == NULL)
313 return (NT_STATUS_NOT_FOUND);
314
315 if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL)
316 return (NT_STATUS_INTERNAL_ERROR);
317
318 if ((domain != NULL) && (smb_strcasecmp(domain, wkadom, 0) != 0))
319 return (NT_STATUS_NONE_MAPPED);
320
321 info->a_name = strdup(name);
322 info->a_sid = smb_sid_dup(wka->wka_binsid);
323 info->a_domain = strdup(wkadom);
324 info->a_domsid = smb_sid_split(wka->wka_binsid, &info->a_rid);
325 info->a_type = wka->wka_type;
326
327 if (!smb_account_validate(info)) {
328 smb_account_free(info);
329 return (NT_STATUS_NO_MEMORY);
330 }
331
332 return (NT_STATUS_SUCCESS);
333 }
334
335 /*
336 * Lookup the given account in domain.
337 *
338 * The information is returned in the user_info structure.
339 * The caller is responsible for allocating and releasing
340 * this structure.
341 */
342 static uint32_t
lsa_lookup_name_domain(char * account_name,smb_account_t * info)343 lsa_lookup_name_domain(char *account_name, smb_account_t *info)
344 {
345 mlsvc_handle_t domain_handle;
346 smb_domainex_t dinfo;
347 uint32_t status;
348 char user[SMB_USERNAME_MAXLEN];
349
350 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
351
352 if (!smb_domain_getinfo(&dinfo))
353 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
354
355 if (lsar_open(dinfo.d_dc, dinfo.d_primary.di_nbname, user,
356 &domain_handle) != 0)
357 return (NT_STATUS_INVALID_PARAMETER);
358
359 status = lsar_lookup_names(&domain_handle, account_name, info);
360
361 (void) lsar_close(&domain_handle);
362 return (status);
363 }
364
365 /*
366 * lsa_lookup_privs
367 *
368 * Request the privileges associated with the specified account. In
369 * order to get the privileges, we first have to lookup the name on
370 * the specified domain controller and obtain the appropriate SID.
371 * The SID can then be used to open the account and obtain the
372 * account privileges. The results from both the name lookup and the
373 * privileges are returned in the user_info structure. The caller is
374 * responsible for allocating and releasing this structure.
375 *
376 * On success 0 is returned. Otherwise a -ve error code.
377 */
378 /*ARGSUSED*/
379 int
lsa_lookup_privs(char * account_name,char * target_name,smb_account_t * ainfo)380 lsa_lookup_privs(char *account_name, char *target_name, smb_account_t *ainfo)
381 {
382 mlsvc_handle_t domain_handle;
383 int rc;
384 smb_domainex_t dinfo;
385 char user[SMB_USERNAME_MAXLEN];
386
387 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
388
389 if (!smb_domain_getinfo(&dinfo))
390 return (-1);
391
392 if ((lsar_open(dinfo.d_dc, dinfo.d_primary.di_nbname, user,
393 &domain_handle)) != 0)
394 return (-1);
395
396 rc = lsa_list_accounts(&domain_handle);
397 (void) lsar_close(&domain_handle);
398 return (rc);
399 }
400
401 /*
402 * lsa_list_privs
403 *
404 * List the privileges supported by the specified server.
405 * This function is only intended for diagnostics.
406 *
407 * Returns NT status codes.
408 */
409 DWORD
lsa_list_privs(char * server,char * domain)410 lsa_list_privs(char *server, char *domain)
411 {
412 static char name[128];
413 static struct ms_luid luid;
414 mlsvc_handle_t domain_handle;
415 int rc;
416 int i;
417 char user[SMB_USERNAME_MAXLEN];
418
419 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
420
421 rc = lsar_open(server, domain, user, &domain_handle);
422 if (rc != 0)
423 return (NT_STATUS_INVALID_PARAMETER);
424
425 for (i = 0; i < 30; ++i) {
426 luid.low_part = i;
427 rc = lsar_lookup_priv_name(&domain_handle, &luid, name, 128);
428 if (rc != 0)
429 continue;
430
431 (void) lsar_lookup_priv_value(&domain_handle, name, &luid);
432 (void) lsar_lookup_priv_display_name(&domain_handle, name,
433 name, 128);
434 }
435
436 (void) lsar_close(&domain_handle);
437 return (NT_STATUS_SUCCESS);
438 }
439
440 /*
441 * lsa_list_accounts
442 *
443 * This function can be used to list the accounts in the specified
444 * domain. For now the SIDs are just listed in the system log.
445 *
446 * On success 0 is returned. Otherwise a -ve error code.
447 */
448 static int
lsa_list_accounts(mlsvc_handle_t * domain_handle)449 lsa_list_accounts(mlsvc_handle_t *domain_handle)
450 {
451 mlsvc_handle_t account_handle;
452 struct mslsa_EnumAccountBuf accounts;
453 struct mslsa_sid *sid;
454 smb_account_t ainfo;
455 DWORD enum_context = 0;
456 int rc;
457 int i;
458
459 bzero(&accounts, sizeof (struct mslsa_EnumAccountBuf));
460
461 do {
462 rc = lsar_enum_accounts(domain_handle, &enum_context,
463 &accounts);
464 if (rc != 0)
465 return (rc);
466
467 for (i = 0; i < accounts.entries_read; ++i) {
468 sid = accounts.info[i].sid;
469
470 if (lsar_open_account(domain_handle, sid,
471 &account_handle) == 0) {
472 (void) lsar_enum_privs_account(&account_handle,
473 &ainfo);
474 (void) lsar_close(&account_handle);
475 }
476
477 free(accounts.info[i].sid);
478 }
479
480 if (accounts.info)
481 free(accounts.info);
482 } while (rc == 0 && accounts.entries_read != 0);
483
484 return (0);
485 }
486
487 /*
488 * Lookup well known accounts table for the given SID
489 *
490 * Return status:
491 *
492 * NT_STATUS_SUCCESS Account is translated successfully
493 * NT_STATUS_NOT_FOUND This is not a well known account
494 * NT_STATUS_NO_MEMORY Memory shortage
495 * NT_STATUS_INTERNAL_ERROR Internal error/unexpected failure
496 */
497 static uint32_t
lsa_lookup_sid_builtin(smb_sid_t * sid,smb_account_t * ainfo)498 lsa_lookup_sid_builtin(smb_sid_t *sid, smb_account_t *ainfo)
499 {
500 smb_wka_t *wka;
501 char *wkadom;
502
503 bzero(ainfo, sizeof (smb_account_t));
504
505 if ((wka = smb_wka_lookup_sid(sid)) == NULL)
506 return (NT_STATUS_NOT_FOUND);
507
508 if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL)
509 return (NT_STATUS_INTERNAL_ERROR);
510
511 ainfo->a_name = strdup(wka->wka_name);
512 ainfo->a_sid = smb_sid_dup(wka->wka_binsid);
513 ainfo->a_domain = strdup(wkadom);
514 ainfo->a_domsid = smb_sid_split(ainfo->a_sid, &ainfo->a_rid);
515 ainfo->a_type = wka->wka_type;
516
517 if (!smb_account_validate(ainfo)) {
518 smb_account_free(ainfo);
519 return (NT_STATUS_NO_MEMORY);
520 }
521
522 return (NT_STATUS_SUCCESS);
523 }
524
525 static uint32_t
lsa_lookup_sid_domain(smb_sid_t * sid,smb_account_t * ainfo)526 lsa_lookup_sid_domain(smb_sid_t *sid, smb_account_t *ainfo)
527 {
528 mlsvc_handle_t domain_handle;
529 uint32_t status;
530 smb_domainex_t dinfo;
531 char user[SMB_USERNAME_MAXLEN];
532
533 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
534
535 if (!smb_domain_getinfo(&dinfo))
536 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
537
538 if (lsar_open(dinfo.d_dc, dinfo.d_primary.di_nbname, user,
539 &domain_handle) != 0)
540 return (NT_STATUS_INVALID_PARAMETER);
541
542 status = lsar_lookup_sids(&domain_handle, sid, ainfo);
543
544 (void) lsar_close(&domain_handle);
545 return (status);
546 }
547