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.
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.
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]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
36 #include <smbsrv/libsmb.h>
37 #include <smbsrv/wintypes.h>
38 #include <smbsrv/smb_door.h>
40 static int smb_door_call(uint32_t, void *, xdrproc_t
, void *, xdrproc_t
);
41 static int smb_door_call_private(int, smb_doorarg_t
*);
42 static int smb_door_encode(smb_doorarg_t
*, uint32_t);
43 static int smb_door_decode(smb_doorarg_t
*);
44 static void smb_door_sethdr(smb_doorhdr_t
*, uint32_t, uint32_t);
45 static boolean_t
smb_door_chkhdr(smb_doorarg_t
*, smb_doorhdr_t
*);
46 static void smb_door_free(door_arg_t
*arg
);
49 * Given a SID, make a door call to get the associated name.
51 * Returns 0 if the door call is successful, otherwise -1.
53 * If 0 is returned, the lookup result will be available in a_status.
54 * NT_STATUS_SUCCESS The SID was mapped to a name.
55 * NT_STATUS_NONE_MAPPED The SID could not be mapped to a name.
58 smb_lookup_sid(const char *sid
, lsa_account_t
*acct
)
62 assert((sid
!= NULL
) && (acct
!= NULL
));
64 bzero(acct
, sizeof (lsa_account_t
));
65 (void) strlcpy(acct
->a_sid
, sid
, SMB_SID_STRSZ
);
67 rc
= smb_door_call(SMB_DR_LOOKUP_SID
, acct
, lsa_account_xdr
,
68 acct
, lsa_account_xdr
);
71 syslog(LOG_DEBUG
, "smb_lookup_sid: %m");
76 * Given a name, make a door call to get the associated SID.
78 * Returns 0 if the door call is successful, otherwise -1.
80 * If 0 is returned, the lookup result will be available in a_status.
81 * NT_STATUS_SUCCESS The name was mapped to a SID.
82 * NT_STATUS_NONE_MAPPED The name could not be mapped to a SID.
85 smb_lookup_name(const char *name
, sid_type_t sidtype
, lsa_account_t
*acct
)
92 assert((name
!= NULL
) && (acct
!= NULL
));
94 (void) strlcpy(tmp
, name
, MAXNAMELEN
);
95 smb_name_parse(tmp
, &np
, &dp
);
97 bzero(acct
, sizeof (lsa_account_t
));
98 acct
->a_sidtype
= sidtype
;
100 if (dp
!= NULL
&& np
!= NULL
) {
101 (void) strlcpy(acct
->a_domain
, dp
, MAXNAMELEN
);
102 (void) strlcpy(acct
->a_name
, np
, MAXNAMELEN
);
104 (void) strlcpy(acct
->a_name
, name
, MAXNAMELEN
);
107 rc
= smb_door_call(SMB_DR_LOOKUP_NAME
, acct
, lsa_account_xdr
,
108 acct
, lsa_account_xdr
);
111 syslog(LOG_DEBUG
, "smb_lookup_name: %m");
116 smb_join(smb_joininfo_t
*jdi
, smb_joinres_t
*jres
)
120 rc
= smb_door_call(SMB_DR_JOIN
, jdi
, smb_joininfo_xdr
,
121 jres
, smb_joinres_xdr
);
125 * This usually means the SMB service is not running.
127 syslog(LOG_DEBUG
, "smb_join: %m");
128 jres
->status
= NT_STATUS_SERVER_DISABLED
;
136 * Get information about the Domain Controller in the joined resource domain.
138 * Returns NT status codes.
141 smb_get_dcinfo(char *namebuf
, uint32_t namebuflen
, smb_inaddr_t
*ipaddr
)
147 assert((namebuf
!= NULL
) && (namebuflen
!= 0));
149 bzero(&dcname
, sizeof (smb_string_t
));
151 rc
= smb_door_call(SMB_DR_GET_DCINFO
, NULL
, NULL
,
152 &dcname
, smb_string_xdr
);
155 syslog(LOG_DEBUG
, "smb_get_dcinfo: %m");
157 xdr_free(smb_string_xdr
, (char *)&dcname
);
158 return (NT_STATUS_INTERNAL_ERROR
);
162 (void) strlcpy(namebuf
, dcname
.buf
, namebuflen
);
164 if ((h
= smb_gethostbyname(dcname
.buf
, &rc
)) == NULL
) {
165 bzero(ipaddr
, sizeof (smb_inaddr_t
));
167 (void) memcpy(ipaddr
, h
->h_addr
, h
->h_length
);
168 ipaddr
->a_family
= h
->h_addrtype
;
171 xdr_free(smb_string_xdr
, (char *)&dcname
);
174 return (NT_STATUS_SUCCESS
);
178 smb_joininfo_xdr(XDR
*xdrs
, smb_joininfo_t
*objp
)
180 if (!xdr_vector(xdrs
, (char *)objp
->domain_name
, MAXHOSTNAMELEN
,
181 sizeof (char), (xdrproc_t
)xdr_char
))
184 if (!xdr_vector(xdrs
, (char *)objp
->domain_username
,
185 SMB_USERNAME_MAXLEN
+ 1, sizeof (char), (xdrproc_t
)xdr_char
))
188 if (!xdr_vector(xdrs
, (char *)objp
->domain_passwd
,
189 SMB_PASSWD_MAXLEN
+ 1, sizeof (char), (xdrproc_t
)xdr_char
))
192 if (!xdr_uint32_t(xdrs
, &objp
->mode
))
199 smb_joinres_xdr(XDR
*xdrs
, smb_joinres_t
*objp
)
202 if (!xdr_uint32_t(xdrs
, &objp
->status
))
205 if (!xdr_int(xdrs
, &objp
->join_err
))
208 if (!xdr_vector(xdrs
, (char *)objp
->dc_name
, MAXHOSTNAMELEN
,
209 sizeof (char), (xdrproc_t
)xdr_char
))
217 * fqdn (input) - fully-qualified domain name
218 * buf (output) - fully-qualified hostname of the AD server found
220 * buflen (input) - length of the 'buf'
223 * B_TRUE if an AD server is found. Otherwise, returns B_FALSE;
225 * The buffer passed in should be big enough to hold a fully-qualified
226 * hostname (MAXHOSTNAMELEN); otherwise, a truncated string will be
227 * returned. On error, an empty string will be returned.
230 smb_find_ads_server(char *fqdn
, char *buf
, int buflen
)
234 boolean_t found
= B_FALSE
;
237 if (fqdn
== NULL
|| buf
== NULL
) {
243 bzero(&server
, sizeof (smb_string_t
));
248 rc
= smb_door_call(SMB_DR_ADS_FIND_HOST
, &domain
, smb_string_xdr
,
249 &server
, smb_string_xdr
);
252 syslog(LOG_DEBUG
, "smb_find_ads_server: %m");
254 if (server
.buf
!= NULL
) {
255 if (*server
.buf
!= '\0') {
256 (void) strlcpy(buf
, server
.buf
, buflen
);
260 xdr_free(smb_string_xdr
, (char *)&server
);
267 smb_notify_dc_changed(void)
271 rc
= smb_door_call(SMB_DR_NOTIFY_DC_CHANGED
,
272 NULL
, NULL
, NULL
, NULL
);
275 syslog(LOG_DEBUG
, "smb_notify_dc_changed: %m");
280 * After a successful door call the local door_arg->data_ptr is assigned
281 * to the caller's arg->rbuf so that arg has references to both input and
282 * response buffers, which is required by smb_door_free.
284 * On success, the object referenced by rsp_data will have been populated
285 * by passing rbuf through the rsp_xdr function.
288 smb_door_call(uint32_t cmd
, void *req_data
, xdrproc_t req_xdr
,
289 void *rsp_data
, xdrproc_t rsp_xdr
)
296 bzero(&da
, sizeof (smb_doorarg_t
));
298 da
.da_opname
= smb_doorhdr_opname(cmd
);
299 da
.da_req_xdr
= req_xdr
;
300 da
.da_rsp_xdr
= rsp_xdr
;
301 da
.da_req_data
= req_data
;
302 da
.da_rsp_data
= rsp_data
;
304 if ((req_data
== NULL
&& req_xdr
!= NULL
) ||
305 (rsp_data
== NULL
&& rsp_xdr
!= NULL
)) {
307 syslog(LOG_DEBUG
, "smb_door_call[%s]: %m", da
.da_opname
);
311 door_name
= getenv("SMBD_DOOR_NAME");
312 if (door_name
== NULL
)
313 door_name
= SMBD_DOOR_NAME
;
315 if ((fd
= open(door_name
, O_RDONLY
)) < 0) {
316 syslog(LOG_DEBUG
, "smb_door_call[%s]: %m", da
.da_opname
);
320 if (smb_door_encode(&da
, cmd
) != 0) {
321 syslog(LOG_DEBUG
, "smb_door_call[%s]: %m", da
.da_opname
);
326 if (smb_door_call_private(fd
, &da
) != 0) {
327 syslog(LOG_DEBUG
, "smb_door_call[%s]: %m", da
.da_opname
);
328 smb_door_free(&da
.da_arg
);
333 if ((rc
= smb_door_decode(&da
)) != 0)
334 syslog(LOG_DEBUG
, "smb_door_call[%s]: %m", da
.da_opname
);
335 smb_door_free(&da
.da_arg
);
341 * We use a copy of the door arg because doorfs may change data_ptr
342 * and we want to detect that when freeing the door buffers. After
343 * this call, response data must be referenced via rbuf and rsize.
346 smb_door_call_private(int fd
, smb_doorarg_t
*da
)
352 bcopy(&da
->da_arg
, &door_arg
, sizeof (door_arg_t
));
354 for (i
= 0; i
< SMB_DOOR_CALL_RETRIES
; ++i
) {
357 if ((rc
= door_call(fd
, &door_arg
)) == 0)
360 if (errno
!= EAGAIN
&& errno
!= EINTR
)
364 if (rc
!= 0 || door_arg
.data_size
== 0 || door_arg
.rsize
== 0) {
370 da
->da_arg
.rbuf
= door_arg
.data_ptr
;
371 da
->da_arg
.rsize
= door_arg
.rsize
;
376 smb_door_encode(smb_doorarg_t
*da
, uint32_t cmd
)
382 buflen
= xdr_sizeof(smb_doorhdr_xdr
, &da
->da_hdr
);
383 if (da
->da_req_xdr
!= NULL
)
384 buflen
+= xdr_sizeof(da
->da_req_xdr
, da
->da_req_data
);
386 smb_door_sethdr(&da
->da_hdr
, cmd
, buflen
);
388 if ((buf
= malloc(buflen
)) == NULL
)
391 xdrmem_create(&xdrs
, buf
, buflen
, XDR_ENCODE
);
393 if (!smb_doorhdr_xdr(&xdrs
, &da
->da_hdr
)) {
400 if (da
->da_req_xdr
!= NULL
) {
401 if (!da
->da_req_xdr(&xdrs
, da
->da_req_data
)) {
409 da
->da_arg
.data_ptr
= buf
;
410 da
->da_arg
.data_size
= buflen
;
411 da
->da_arg
.desc_ptr
= NULL
;
412 da
->da_arg
.desc_num
= 0;
413 da
->da_arg
.rbuf
= buf
;
414 da
->da_arg
.rsize
= buflen
;
421 * Decode the response in rbuf and rsize.
424 smb_door_decode(smb_doorarg_t
*da
)
428 char *rbuf
= da
->da_arg
.rbuf
;
429 uint32_t rsize
= da
->da_arg
.rsize
;
431 if (rbuf
== NULL
|| rsize
== 0) {
436 xdrmem_create(&xdrs
, rbuf
, rsize
, XDR_DECODE
);
438 if (!smb_doorhdr_xdr(&xdrs
, &hdr
)) {
444 if (!smb_door_chkhdr(da
, &hdr
)) {
450 if (da
->da_rsp_xdr
!= NULL
) {
451 if (!da
->da_rsp_xdr(&xdrs
, da
->da_rsp_data
)) {
463 smb_door_sethdr(smb_doorhdr_t
*hdr
, uint32_t cmd
, uint32_t datalen
)
465 bzero(hdr
, sizeof (smb_doorhdr_t
));
466 hdr
->dh_magic
= SMB_DOOR_HDR_MAGIC
;
467 hdr
->dh_flags
= SMB_DF_USERSPACE
;
469 hdr
->dh_txid
= smb_get_txid();
470 hdr
->dh_datalen
= datalen
;
471 hdr
->dh_door_rc
= SMB_DOP_NOT_CALLED
;
475 smb_door_chkhdr(smb_doorarg_t
*da
, smb_doorhdr_t
*hdr
)
477 if ((hdr
->dh_magic
!= SMB_DOOR_HDR_MAGIC
) ||
478 (hdr
->dh_op
!= da
->da_hdr
.dh_op
) ||
479 (hdr
->dh_txid
!= da
->da_hdr
.dh_txid
)) {
480 syslog(LOG_DEBUG
, "smb_door_chkhdr[%s]: invalid header",
485 if (hdr
->dh_door_rc
!= SMB_DOP_SUCCESS
) {
486 syslog(LOG_DEBUG
, "smb_door_chkhdr[%s]: call status=%d",
487 da
->da_opname
, hdr
->dh_door_rc
);
495 * Free resources allocated for a door call. If the result buffer provided
496 * by the client is too small, doorfs will have allocated a new buffer,
497 * which must be unmapped here.
499 * This function must be called to free both the argument and result door
500 * buffers regardless of the status of the door call.
503 smb_door_free(door_arg_t
*arg
)
505 if (arg
->rbuf
&& (arg
->rbuf
!= arg
->data_ptr
))
506 (void) munmap(arg
->rbuf
, arg
->rsize
);