112b65585SGordon Ross /*
212b65585SGordon Ross * This file and its contents are supplied under the terms of the
312b65585SGordon Ross * Common Development and Distribution License ("CDDL"), version 1.0.
412b65585SGordon Ross * You may only use this file in accordance with the terms of version
512b65585SGordon Ross * 1.0 of the CDDL.
612b65585SGordon Ross *
712b65585SGordon Ross * A full copy of the text of the CDDL should have accompanied this
812b65585SGordon Ross * source. A copy of the CDDL is also available via the Internet at
912b65585SGordon Ross * http://www.illumos.org/license/CDDL.
1012b65585SGordon Ross */
1112b65585SGordon Ross
1212b65585SGordon Ross /*
13975041ddSGordon Ross * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
14*5d8538b6SGordon Ross * Copyright 2022-2023 RackTop Systems, Inc.
1512b65585SGordon Ross */
1612b65585SGordon Ross
1712b65585SGordon Ross /*
1812b65585SGordon Ross * SMB authentication service
1912b65585SGordon Ross *
2012b65585SGordon Ross * This service listens on a local AF_UNIX socket, spawning a
2112b65585SGordon Ross * thread to service each connection. The client-side of such
2212b65585SGordon Ross * connections is the in-kernel SMB service, with an open and
2312b65585SGordon Ross * connect done in the SMB session setup handler.
2412b65585SGordon Ross */
2512b65585SGordon Ross
2612b65585SGordon Ross #include <sys/types.h>
2712b65585SGordon Ross #include <stdlib.h>
2812b65585SGordon Ross #include <errno.h>
2912b65585SGordon Ross #include <string.h>
3012b65585SGordon Ross #include <strings.h>
3112b65585SGordon Ross #include <unistd.h>
3212b65585SGordon Ross #include <signal.h>
3312b65585SGordon Ross #include <stdio.h>
3412b65585SGordon Ross #include <note.h>
3512b65585SGordon Ross #include <net/if.h>
3612b65585SGordon Ross #include <net/route.h>
3712b65585SGordon Ross #include <sys/sockio.h>
3812b65585SGordon Ross #include <sys/socket.h>
3912b65585SGordon Ross #include <sys/un.h>
4012b65585SGordon Ross #include <netinet/in.h>
4112b65585SGordon Ross #include <fcntl.h>
4212b65585SGordon Ross #include <pthread.h>
4312b65585SGordon Ross #include <syslog.h>
44b6b7639aSGordon Ross #include <ucred.h>
45b6b7639aSGordon Ross #include <priv.h>
46b6b7639aSGordon Ross
4712b65585SGordon Ross #include <smbsrv/libsmb.h>
4812b65585SGordon Ross #include <netsmb/spnego.h>
4912b65585SGordon Ross
5012b65585SGordon Ross #include "smbd.h"
5112b65585SGordon Ross #include "smbd_authsvc.h"
5212b65585SGordon Ross
5312b65585SGordon Ross /* Arbitrary value outside the (small) range of valid OIDs */
5412b65585SGordon Ross #define special_mech_raw_NTLMSSP (spnego_mech_oid_NTLMSSP + 100)
5512b65585SGordon Ross
5612b65585SGordon Ross static struct sockaddr_un smbauth_sockname = {
5712b65585SGordon Ross AF_UNIX, SMB_AUTHSVC_SOCKNAME };
5812b65585SGordon Ross
5912b65585SGordon Ross typedef struct spnego_mech_handler {
6012b65585SGordon Ross int mh_oid; /* SPNEGO_MECH_OID */
6112b65585SGordon Ross int (*mh_init)(authsvc_context_t *);
6212b65585SGordon Ross int (*mh_work)(authsvc_context_t *);
6312b65585SGordon Ross void (*mh_fini)(authsvc_context_t *);
6412b65585SGordon Ross } spnego_mech_handler_t;
6512b65585SGordon Ross
6612b65585SGordon Ross static int smbd_authsock_create(void);
6712b65585SGordon Ross static void smbd_authsock_destroy(void);
6812b65585SGordon Ross static void *smbd_authsvc_listen(void *);
6912b65585SGordon Ross static void *smbd_authsvc_work(void *);
7012b65585SGordon Ross static void smbd_authsvc_flood(void);
7112b65585SGordon Ross
7212b65585SGordon Ross static int smbd_authsvc_oldreq(authsvc_context_t *);
7312b65585SGordon Ross static int smbd_authsvc_clinfo(authsvc_context_t *);
7412b65585SGordon Ross static int smbd_authsvc_esfirst(authsvc_context_t *);
7512b65585SGordon Ross static int smbd_authsvc_esnext(authsvc_context_t *);
7612b65585SGordon Ross static int smbd_authsvc_escmn(authsvc_context_t *);
77cc86afeeSGordon Ross static int smbd_authsvc_newmech(authsvc_context_t *);
7812b65585SGordon Ross static int smbd_authsvc_gettoken(authsvc_context_t *);
7912b65585SGordon Ross static int smbd_raw_ntlmssp_esfirst(authsvc_context_t *);
8012b65585SGordon Ross static int smbd_raw_ntlmssp_esnext(authsvc_context_t *);
8112b65585SGordon Ross
8212b65585SGordon Ross /*
8312b65585SGordon Ross * We can get relatively large tokens now, thanks to krb5 PAC.
8412b65585SGordon Ross * Might be better to size these buffers dynamically, but these
8512b65585SGordon Ross * are all short-lived so not bothering with that for now.
8612b65585SGordon Ross */
8712b65585SGordon Ross int smbd_authsvc_bufsize = 65000;
8812b65585SGordon Ross
8912b65585SGordon Ross static mutex_t smbd_authsvc_mutex = DEFAULTMUTEX;
9012b65585SGordon Ross
9112b65585SGordon Ross /*
9212b65585SGordon Ross * The maximum number of authentication thread is limited by the
9312b65585SGordon Ross * smbsrv smb_threshold_...(->sv_ssetup_ct) mechanism. However,
9412b65585SGordon Ross * due to occasional delays closing these auth. sockets, we need
9512b65585SGordon Ross * a little "slack" on the number of threads we'll allow, as
9612b65585SGordon Ross * compared with the in-kernel limit. We could perhaps just
9712b65585SGordon Ross * remove this limit now, but want it for extra safety.
9812b65585SGordon Ross */
9912b65585SGordon Ross int smbd_authsvc_maxthread = SMB_AUTHSVC_MAXTHREAD + 32;
10012b65585SGordon Ross int smbd_authsvc_thrcnt = 0; /* current thrcnt */
10112b65585SGordon Ross int smbd_authsvc_hiwat = 0; /* largest thrcnt seen */
10212b65585SGordon Ross #ifdef DEBUG
10312b65585SGordon Ross int smbd_authsvc_slowdown = 0;
10412b65585SGordon Ross #endif
10512b65585SGordon Ross
10612b65585SGordon Ross /*
10712b65585SGordon Ross * These are the mechanisms we support, in order of preference.
10812b65585SGordon Ross * But note: it's really the _client's_ preference that matters.
10912b65585SGordon Ross * See &pref in the spnegoIsMechTypeAvailable() calls below.
11012b65585SGordon Ross * Careful with this table; the code below knows its format and
111a44e7c2cSGordon Ross * may skip the fist two entries to omit Kerberos.
11212b65585SGordon Ross */
11312b65585SGordon Ross static const spnego_mech_handler_t
11412b65585SGordon Ross mech_table[] = {
11512b65585SGordon Ross {
11612b65585SGordon Ross spnego_mech_oid_Kerberos_V5,
11712b65585SGordon Ross smbd_krb5ssp_init,
11812b65585SGordon Ross smbd_krb5ssp_work,
11912b65585SGordon Ross smbd_krb5ssp_fini
12012b65585SGordon Ross },
12112b65585SGordon Ross {
12212b65585SGordon Ross spnego_mech_oid_Kerberos_V5_Legacy,
12312b65585SGordon Ross smbd_krb5ssp_init,
12412b65585SGordon Ross smbd_krb5ssp_work,
12512b65585SGordon Ross smbd_krb5ssp_fini
12612b65585SGordon Ross },
12712b65585SGordon Ross #define MECH_TBL_IDX_NTLMSSP 2
12812b65585SGordon Ross {
12912b65585SGordon Ross spnego_mech_oid_NTLMSSP,
13012b65585SGordon Ross smbd_ntlmssp_init,
13112b65585SGordon Ross smbd_ntlmssp_work,
13212b65585SGordon Ross smbd_ntlmssp_fini
13312b65585SGordon Ross },
13412b65585SGordon Ross {
13512b65585SGordon Ross /* end marker */
13612b65585SGordon Ross spnego_mech_oid_NotUsed,
13712b65585SGordon Ross NULL, NULL, NULL
13812b65585SGordon Ross },
13912b65585SGordon Ross };
14012b65585SGordon Ross
14112b65585SGordon Ross static const spnego_mech_handler_t
14212b65585SGordon Ross smbd_auth_mech_raw_ntlmssp = {
14312b65585SGordon Ross special_mech_raw_NTLMSSP,
14412b65585SGordon Ross smbd_ntlmssp_init,
14512b65585SGordon Ross smbd_ntlmssp_work,
14612b65585SGordon Ross smbd_ntlmssp_fini
14712b65585SGordon Ross };
14812b65585SGordon Ross
14912b65585SGordon Ross
15012b65585SGordon Ross /*
15112b65585SGordon Ross * Start the authentication service.
15212b65585SGordon Ross * Returns non-zero on error.
15312b65585SGordon Ross */
15412b65585SGordon Ross int
smbd_authsvc_start(void)15512b65585SGordon Ross smbd_authsvc_start(void)
15612b65585SGordon Ross {
15712b65585SGordon Ross pthread_attr_t attr;
15812b65585SGordon Ross pthread_t tid;
15912b65585SGordon Ross int rc;
16012b65585SGordon Ross
16112b65585SGordon Ross rc = smbd_authsock_create();
16212b65585SGordon Ross if (rc)
16312b65585SGordon Ross return (rc);
16412b65585SGordon Ross
16512b65585SGordon Ross (void) pthread_attr_init(&attr);
16612b65585SGordon Ross (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
16712b65585SGordon Ross rc = pthread_create(&tid, &attr, smbd_authsvc_listen, &smbd);
16812b65585SGordon Ross (void) pthread_attr_destroy(&attr);
16912b65585SGordon Ross if (rc) {
17012b65585SGordon Ross smbd_authsock_destroy();
17112b65585SGordon Ross return (rc);
17212b65585SGordon Ross }
17312b65585SGordon Ross
17412b65585SGordon Ross smbd.s_authsvc_tid = tid;
17512b65585SGordon Ross return (0);
17612b65585SGordon Ross }
17712b65585SGordon Ross
17812b65585SGordon Ross void
smbd_authsvc_stop(void)17912b65585SGordon Ross smbd_authsvc_stop(void)
18012b65585SGordon Ross {
18112b65585SGordon Ross
18212b65585SGordon Ross if (smbd.s_authsvc_tid != 0) {
18312b65585SGordon Ross (void) pthread_kill(smbd.s_authsvc_tid, SIGTERM);
18412b65585SGordon Ross smbd.s_authsvc_tid = 0;
18512b65585SGordon Ross }
18612b65585SGordon Ross }
18712b65585SGordon Ross
18812b65585SGordon Ross static int
smbd_authsock_create(void)18912b65585SGordon Ross smbd_authsock_create(void)
19012b65585SGordon Ross {
19112b65585SGordon Ross int sock = -1;
19212b65585SGordon Ross
19312b65585SGordon Ross sock = socket(AF_UNIX, SOCK_STREAM, 0);
19412b65585SGordon Ross if (sock < 0) {
19512b65585SGordon Ross smbd_report("authsvc, socket create failed, %d", errno);
19612b65585SGordon Ross return (errno);
19712b65585SGordon Ross }
19812b65585SGordon Ross
19912b65585SGordon Ross (void) unlink(smbauth_sockname.sun_path);
20012b65585SGordon Ross if (bind(sock, (struct sockaddr *)&smbauth_sockname,
20112b65585SGordon Ross sizeof (smbauth_sockname)) < 0) {
20212b65585SGordon Ross smbd_report("authsvc, socket bind failed, %d", errno);
20312b65585SGordon Ross (void) close(sock);
20412b65585SGordon Ross return (errno);
20512b65585SGordon Ross }
20612b65585SGordon Ross
20712b65585SGordon Ross if (listen(sock, SOMAXCONN) < 0) {
20812b65585SGordon Ross smbd_report("authsvc, socket listen failed, %d", errno);
20912b65585SGordon Ross (void) close(sock);
21012b65585SGordon Ross return (errno);
21112b65585SGordon Ross }
21212b65585SGordon Ross
21312b65585SGordon Ross smbd.s_authsvc_sock = sock;
21412b65585SGordon Ross return (0);
21512b65585SGordon Ross }
21612b65585SGordon Ross
21712b65585SGordon Ross static void
smbd_authsock_destroy(void)21812b65585SGordon Ross smbd_authsock_destroy(void)
21912b65585SGordon Ross {
22012b65585SGordon Ross int fid;
22112b65585SGordon Ross
22212b65585SGordon Ross if ((fid = smbd.s_authsvc_sock) != -1) {
22312b65585SGordon Ross smbd.s_authsvc_sock = -1;
22412b65585SGordon Ross (void) close(fid);
22512b65585SGordon Ross }
22612b65585SGordon Ross }
22712b65585SGordon Ross
228b6b7639aSGordon Ross #ifndef FKSMBD
229*5d8538b6SGordon Ross /*
230*5d8538b6SGordon Ross * Decide whether to communicate with the client on this AF_UNIX socket.
231*5d8538b6SGordon Ross * Normally the caller should be the (in-kernel) SMB service which has
232*5d8538b6SGordon Ross * (typically) all privileges. We test for PRIV_SYS_SMB here, which
233*5d8538b6SGordon Ross * only the SMB service should have.
234*5d8538b6SGordon Ross */
235b6b7639aSGordon Ross static boolean_t
authsock_has_priv(int sock)236b6b7639aSGordon Ross authsock_has_priv(int sock)
237b6b7639aSGordon Ross {
238b6b7639aSGordon Ross ucred_t *uc = NULL;
239b6b7639aSGordon Ross const priv_set_t *ps = NULL;
240b6b7639aSGordon Ross boolean_t ret = B_FALSE;
241b6b7639aSGordon Ross pid_t clpid;
242b6b7639aSGordon Ross
243b6b7639aSGordon Ross if (getpeerucred(sock, &uc) != 0) {
244b6b7639aSGordon Ross smbd_report("authsvc: getpeerucred err %d", errno);
245b6b7639aSGordon Ross return (B_FALSE);
246b6b7639aSGordon Ross }
247b6b7639aSGordon Ross clpid = ucred_getpid(uc);
248b6b7639aSGordon Ross ps = ucred_getprivset(uc, PRIV_EFFECTIVE);
249b6b7639aSGordon Ross if (ps == NULL) {
250b6b7639aSGordon Ross smbd_report("authsvc: ucred_getprivset failed");
251b6b7639aSGordon Ross goto out;
252b6b7639aSGordon Ross }
253b6b7639aSGordon Ross
254b6b7639aSGordon Ross /*
255*5d8538b6SGordon Ross * Require sys_smb priv.
256b6b7639aSGordon Ross */
257b6b7639aSGordon Ross if (priv_ismember(ps, PRIV_SYS_SMB)) {
258b6b7639aSGordon Ross ret = B_TRUE;
259b6b7639aSGordon Ross goto out;
260b6b7639aSGordon Ross }
261b6b7639aSGordon Ross
262b6b7639aSGordon Ross if (smbd.s_debug) {
263b6b7639aSGordon Ross smbd_report("authsvc: non-privileged client "
264b6b7639aSGordon Ross "PID = %d UID = %d",
265b6b7639aSGordon Ross (int)clpid, ucred_getruid(uc));
266b6b7639aSGordon Ross }
267b6b7639aSGordon Ross
268b6b7639aSGordon Ross out:
269b6b7639aSGordon Ross /* ps is free'd with the ucred */
270b6b7639aSGordon Ross if (uc != NULL)
271b6b7639aSGordon Ross ucred_free(uc);
272b6b7639aSGordon Ross
273b6b7639aSGordon Ross return (ret);
274b6b7639aSGordon Ross }
275b6b7639aSGordon Ross #endif
276b6b7639aSGordon Ross
277b6b7639aSGordon Ross
27812b65585SGordon Ross static void *
smbd_authsvc_listen(void * arg)27912b65585SGordon Ross smbd_authsvc_listen(void *arg)
28012b65585SGordon Ross {
28112b65585SGordon Ross authsvc_context_t *ctx;
28212b65585SGordon Ross pthread_attr_t attr;
28312b65585SGordon Ross pthread_t tid;
28412b65585SGordon Ross socklen_t slen;
28512b65585SGordon Ross int ls, ns, rc;
28612b65585SGordon Ross
28712b65585SGordon Ross _NOTE(ARGUNUSED(arg))
28812b65585SGordon Ross
28912b65585SGordon Ross (void) pthread_attr_init(&attr);
29012b65585SGordon Ross (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
29112b65585SGordon Ross
29212b65585SGordon Ross ls = smbd.s_authsvc_sock;
29312b65585SGordon Ross for (;;) {
29412b65585SGordon Ross
29512b65585SGordon Ross slen = 0;
29612b65585SGordon Ross ns = accept(ls, NULL, &slen);
29712b65585SGordon Ross if (ns < 0) {
29812b65585SGordon Ross switch (errno) {
29912b65585SGordon Ross case ECONNABORTED:
30012b65585SGordon Ross continue;
30112b65585SGordon Ross case EINTR:
30212b65585SGordon Ross /* normal termination */
30312b65585SGordon Ross goto out;
30412b65585SGordon Ross default:
30512b65585SGordon Ross smbd_report("authsvc, socket accept failed,"
30612b65585SGordon Ross " %d", errno);
30712b65585SGordon Ross goto out;
30812b65585SGordon Ross }
30912b65585SGordon Ross }
31012b65585SGordon Ross
311b6b7639aSGordon Ross #ifndef FKSMBD
312b6b7639aSGordon Ross if (!authsock_has_priv(ns)) {
313b6b7639aSGordon Ross close(ns);
314b6b7639aSGordon Ross continue;
315b6b7639aSGordon Ross }
316b6b7639aSGordon Ross #endif
317b6b7639aSGordon Ross
31812b65585SGordon Ross /*
31912b65585SGordon Ross * Limit the number of auth. sockets
32012b65585SGordon Ross * (and the threads that service them).
32112b65585SGordon Ross */
32212b65585SGordon Ross (void) mutex_lock(&smbd_authsvc_mutex);
32312b65585SGordon Ross if (smbd_authsvc_thrcnt >= smbd_authsvc_maxthread) {
32412b65585SGordon Ross (void) mutex_unlock(&smbd_authsvc_mutex);
32512b65585SGordon Ross (void) close(ns);
32612b65585SGordon Ross smbd_authsvc_flood();
32712b65585SGordon Ross continue;
32812b65585SGordon Ross }
32912b65585SGordon Ross smbd_authsvc_thrcnt++;
33012b65585SGordon Ross if (smbd_authsvc_hiwat < smbd_authsvc_thrcnt)
33112b65585SGordon Ross smbd_authsvc_hiwat = smbd_authsvc_thrcnt;
33212b65585SGordon Ross (void) mutex_unlock(&smbd_authsvc_mutex);
33312b65585SGordon Ross
33412b65585SGordon Ross ctx = smbd_authctx_create();
33512b65585SGordon Ross if (ctx == NULL) {
33612b65585SGordon Ross smbd_report("authsvc, can't allocate context");
33712b65585SGordon Ross (void) mutex_lock(&smbd_authsvc_mutex);
33812b65585SGordon Ross smbd_authsvc_thrcnt--;
33912b65585SGordon Ross (void) mutex_unlock(&smbd_authsvc_mutex);
34012b65585SGordon Ross (void) close(ns);
3416926de2eSGordon Ross smbd_nomem();
34212b65585SGordon Ross }
34312b65585SGordon Ross ctx->ctx_socket = ns;
34412b65585SGordon Ross
34512b65585SGordon Ross rc = pthread_create(&tid, &attr, smbd_authsvc_work, ctx);
34612b65585SGordon Ross if (rc) {
34712b65585SGordon Ross smbd_report("authsvc, thread create failed, %d", rc);
34812b65585SGordon Ross (void) mutex_lock(&smbd_authsvc_mutex);
34912b65585SGordon Ross smbd_authsvc_thrcnt--;
35012b65585SGordon Ross (void) mutex_unlock(&smbd_authsvc_mutex);
35112b65585SGordon Ross smbd_authctx_destroy(ctx);
3526926de2eSGordon Ross ctx = NULL;
3536926de2eSGordon Ross smbd_nomem();
35412b65585SGordon Ross }
3552a2a3aabSGordon Ross ctx = NULL; /* given to the new thread or destroyed */
3566926de2eSGordon Ross (void) pthread_detach(tid);
35712b65585SGordon Ross }
35812b65585SGordon Ross
35912b65585SGordon Ross out:
36012b65585SGordon Ross (void) pthread_attr_destroy(&attr);
36112b65585SGordon Ross smbd_authsock_destroy();
36212b65585SGordon Ross return (NULL);
36312b65585SGordon Ross }
36412b65585SGordon Ross
36512b65585SGordon Ross static void
smbd_authsvc_flood(void)36612b65585SGordon Ross smbd_authsvc_flood(void)
36712b65585SGordon Ross {
36812b65585SGordon Ross static uint_t count;
36912b65585SGordon Ross static time_t last_report;
37012b65585SGordon Ross time_t now = time(NULL);
37112b65585SGordon Ross
37212b65585SGordon Ross count++;
37312b65585SGordon Ross if (last_report + 60 < now) {
37412b65585SGordon Ross last_report = now;
37512b65585SGordon Ross smbd_report("authsvc: flooded %u", count);
37612b65585SGordon Ross count = 0;
37712b65585SGordon Ross }
37812b65585SGordon Ross }
37912b65585SGordon Ross
38012b65585SGordon Ross authsvc_context_t *
smbd_authctx_create(void)38112b65585SGordon Ross smbd_authctx_create(void)
38212b65585SGordon Ross {
38312b65585SGordon Ross authsvc_context_t *ctx;
38412b65585SGordon Ross
38512b65585SGordon Ross ctx = malloc(sizeof (*ctx));
38612b65585SGordon Ross if (ctx == NULL)
38712b65585SGordon Ross return (NULL);
38812b65585SGordon Ross bzero(ctx, sizeof (*ctx));
38912b65585SGordon Ross
39012b65585SGordon Ross ctx->ctx_irawlen = smbd_authsvc_bufsize;
39112b65585SGordon Ross ctx->ctx_irawbuf = malloc(ctx->ctx_irawlen);
39212b65585SGordon Ross ctx->ctx_orawlen = smbd_authsvc_bufsize;
39312b65585SGordon Ross ctx->ctx_orawbuf = malloc(ctx->ctx_orawlen);
39412b65585SGordon Ross if (ctx->ctx_irawbuf == NULL || ctx->ctx_orawbuf == NULL)
39512b65585SGordon Ross goto errout;
39612b65585SGordon Ross
39712b65585SGordon Ross ctx->ctx_ibodylen = smbd_authsvc_bufsize;
39812b65585SGordon Ross ctx->ctx_ibodybuf = malloc(ctx->ctx_ibodylen);
39912b65585SGordon Ross ctx->ctx_obodylen = smbd_authsvc_bufsize;
40012b65585SGordon Ross ctx->ctx_obodybuf = malloc(ctx->ctx_obodylen);
40112b65585SGordon Ross if (ctx->ctx_ibodybuf == NULL || ctx->ctx_obodybuf == NULL)
40212b65585SGordon Ross goto errout;
40312b65585SGordon Ross
40412b65585SGordon Ross return (ctx);
40512b65585SGordon Ross
40612b65585SGordon Ross errout:
40712b65585SGordon Ross smbd_authctx_destroy(ctx);
40812b65585SGordon Ross return (NULL);
40912b65585SGordon Ross }
41012b65585SGordon Ross
41112b65585SGordon Ross void
smbd_authctx_destroy(authsvc_context_t * ctx)41212b65585SGordon Ross smbd_authctx_destroy(authsvc_context_t *ctx)
41312b65585SGordon Ross {
41412b65585SGordon Ross if (ctx->ctx_socket != -1) {
41512b65585SGordon Ross (void) close(ctx->ctx_socket);
41612b65585SGordon Ross ctx->ctx_socket = -1;
41712b65585SGordon Ross }
41812b65585SGordon Ross
41912b65585SGordon Ross if (ctx->ctx_token != NULL)
42012b65585SGordon Ross smb_token_destroy(ctx->ctx_token);
42112b65585SGordon Ross
42212b65585SGordon Ross if (ctx->ctx_itoken != NULL)
42312b65585SGordon Ross spnegoFreeData(ctx->ctx_itoken);
42412b65585SGordon Ross if (ctx->ctx_otoken != NULL)
42512b65585SGordon Ross spnegoFreeData(ctx->ctx_otoken);
42612b65585SGordon Ross
42712b65585SGordon Ross free(ctx->ctx_irawbuf);
42812b65585SGordon Ross free(ctx->ctx_orawbuf);
42912b65585SGordon Ross free(ctx->ctx_ibodybuf);
43012b65585SGordon Ross free(ctx->ctx_obodybuf);
43112b65585SGordon Ross
43212b65585SGordon Ross free(ctx);
43312b65585SGordon Ross }
43412b65585SGordon Ross
43512b65585SGordon Ross /*
43612b65585SGordon Ross * Limit how long smbd_authsvc_work will wait for the client to
43712b65585SGordon Ross * send us the next part of the authentication sequence.
43812b65585SGordon Ross */
43912b65585SGordon Ross static struct timeval recv_tmo = { 30, 0 };
44012b65585SGordon Ross
44112b65585SGordon Ross /*
44212b65585SGordon Ross * Also set a timeout for send, where we're sending a response to
44312b65585SGordon Ross * the client side (in smbsrv). That should always be waiting in
44412b65585SGordon Ross * recv by the time we send, so a short timeout is OK.
44512b65585SGordon Ross */
44612b65585SGordon Ross static struct timeval send_tmo = { 15, 0 };
44712b65585SGordon Ross
44812b65585SGordon Ross static void *
smbd_authsvc_work(void * arg)44912b65585SGordon Ross smbd_authsvc_work(void *arg)
45012b65585SGordon Ross {
45112b65585SGordon Ross authsvc_context_t *ctx = arg;
45212b65585SGordon Ross smb_lsa_msg_hdr_t hdr;
45312b65585SGordon Ross int sock = ctx->ctx_socket;
45412b65585SGordon Ross int len, rc;
45512b65585SGordon Ross
45612b65585SGordon Ross if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
45712b65585SGordon Ross (char *)&send_tmo, sizeof (send_tmo)) != 0) {
45812b65585SGordon Ross smbd_report("authsvc_work: set set timeout: %m");
45912b65585SGordon Ross goto out;
46012b65585SGordon Ross }
46112b65585SGordon Ross
46212b65585SGordon Ross if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
46312b65585SGordon Ross (char *)&recv_tmo, sizeof (recv_tmo)) != 0) {
46412b65585SGordon Ross smbd_report("authsvc_work: set recv timeout: %m");
46512b65585SGordon Ross goto out;
46612b65585SGordon Ross }
46712b65585SGordon Ross
46812b65585SGordon Ross for (;;) {
46912b65585SGordon Ross
47012b65585SGordon Ross len = recv(sock, &hdr, sizeof (hdr), MSG_WAITALL);
47112b65585SGordon Ross if (len <= 0) {
47212b65585SGordon Ross /* normal termination */
47312b65585SGordon Ross break;
47412b65585SGordon Ross }
47512b65585SGordon Ross if (len != sizeof (hdr)) {
47612b65585SGordon Ross smbd_report("authsvc_work: read header failed");
47712b65585SGordon Ross break;
47812b65585SGordon Ross }
47912b65585SGordon Ross
48012b65585SGordon Ross if (hdr.lmh_msglen > smbd_authsvc_bufsize) {
48112b65585SGordon Ross smbd_report("authsvc_work: msg too large");
48212b65585SGordon Ross break;
48312b65585SGordon Ross }
48412b65585SGordon Ross
48512b65585SGordon Ross if (hdr.lmh_msglen > 0) {
48612b65585SGordon Ross len = recv(sock, ctx->ctx_irawbuf, hdr.lmh_msglen,
48712b65585SGordon Ross MSG_WAITALL);
48812b65585SGordon Ross if (len != hdr.lmh_msglen) {
48912b65585SGordon Ross smbd_report("authsvc_work: read mesg failed");
49012b65585SGordon Ross break;
49112b65585SGordon Ross }
49212b65585SGordon Ross }
49312b65585SGordon Ross ctx->ctx_irawtype = hdr.lmh_msgtype;
49412b65585SGordon Ross ctx->ctx_irawlen = hdr.lmh_msglen;
49512b65585SGordon Ross ctx->ctx_orawlen = smbd_authsvc_bufsize;
49612b65585SGordon Ross ctx->ctx_ibodylen = smbd_authsvc_bufsize;
49712b65585SGordon Ross ctx->ctx_obodylen = smbd_authsvc_bufsize;
49812b65585SGordon Ross
49912b65585SGordon Ross /*
50012b65585SGordon Ross * The real work happens here.
50112b65585SGordon Ross */
50212b65585SGordon Ross rc = smbd_authsvc_dispatch(ctx);
50312b65585SGordon Ross if (rc)
50412b65585SGordon Ross break;
50512b65585SGordon Ross
50612b65585SGordon Ross hdr.lmh_msgtype = ctx->ctx_orawtype;
50712b65585SGordon Ross hdr.lmh_msglen = ctx->ctx_orawlen;
50812b65585SGordon Ross len = send(sock, &hdr, sizeof (hdr), 0);
50912b65585SGordon Ross if (len != sizeof (hdr)) {
51012b65585SGordon Ross smbd_report("authsvc_work: send failed");
51112b65585SGordon Ross break;
51212b65585SGordon Ross }
51312b65585SGordon Ross
51412b65585SGordon Ross if (ctx->ctx_orawlen > 0) {
51512b65585SGordon Ross len = send(sock, ctx->ctx_orawbuf,
51612b65585SGordon Ross ctx->ctx_orawlen, 0);
51712b65585SGordon Ross if (len != ctx->ctx_orawlen) {
51812b65585SGordon Ross smbd_report("authsvc_work: send failed");
51912b65585SGordon Ross break;
52012b65585SGordon Ross }
52112b65585SGordon Ross }
52212b65585SGordon Ross }
52312b65585SGordon Ross
52412b65585SGordon Ross out:
52512b65585SGordon Ross if (ctx->ctx_mh_fini)
52612b65585SGordon Ross (ctx->ctx_mh_fini)(ctx);
52712b65585SGordon Ross
52812b65585SGordon Ross smbd_authctx_destroy(ctx);
52912b65585SGordon Ross
53012b65585SGordon Ross (void) mutex_lock(&smbd_authsvc_mutex);
53112b65585SGordon Ross smbd_authsvc_thrcnt--;
53212b65585SGordon Ross (void) mutex_unlock(&smbd_authsvc_mutex);
53312b65585SGordon Ross
53412b65585SGordon Ross return (NULL); /* implied pthread_exit() */
53512b65585SGordon Ross }
53612b65585SGordon Ross
53712b65585SGordon Ross /*
53812b65585SGordon Ross * Dispatch based on message type LSA_MTYPE_...
53912b65585SGordon Ross * Non-zero return here ends the conversation.
54012b65585SGordon Ross */
54112b65585SGordon Ross int
smbd_authsvc_dispatch(authsvc_context_t * ctx)54212b65585SGordon Ross smbd_authsvc_dispatch(authsvc_context_t *ctx)
54312b65585SGordon Ross {
54412b65585SGordon Ross int rc;
54512b65585SGordon Ross
54612b65585SGordon Ross switch (ctx->ctx_irawtype) {
54712b65585SGordon Ross
54812b65585SGordon Ross case LSA_MTYPE_OLDREQ:
54912b65585SGordon Ross #ifdef DEBUG
55012b65585SGordon Ross if (smbd_authsvc_slowdown)
55112b65585SGordon Ross (void) sleep(smbd_authsvc_slowdown);
55212b65585SGordon Ross #endif
55312b65585SGordon Ross rc = smbd_authsvc_oldreq(ctx);
55412b65585SGordon Ross break;
55512b65585SGordon Ross
55612b65585SGordon Ross case LSA_MTYPE_CLINFO:
55712b65585SGordon Ross rc = smbd_authsvc_clinfo(ctx);
55812b65585SGordon Ross break;
55912b65585SGordon Ross
56012b65585SGordon Ross case LSA_MTYPE_ESFIRST:
56112b65585SGordon Ross rc = smbd_authsvc_esfirst(ctx);
56212b65585SGordon Ross break;
56312b65585SGordon Ross
56412b65585SGordon Ross case LSA_MTYPE_ESNEXT:
56512b65585SGordon Ross #ifdef DEBUG
56612b65585SGordon Ross if (smbd_authsvc_slowdown)
56712b65585SGordon Ross (void) sleep(smbd_authsvc_slowdown);
56812b65585SGordon Ross #endif
56912b65585SGordon Ross rc = smbd_authsvc_esnext(ctx);
57012b65585SGordon Ross break;
57112b65585SGordon Ross
57212b65585SGordon Ross case LSA_MTYPE_GETTOK:
57312b65585SGordon Ross rc = smbd_authsvc_gettoken(ctx);
57412b65585SGordon Ross break;
57512b65585SGordon Ross
57612b65585SGordon Ross /* response types */
57712b65585SGordon Ross case LSA_MTYPE_OK:
57812b65585SGordon Ross case LSA_MTYPE_ERROR:
57912b65585SGordon Ross case LSA_MTYPE_TOKEN:
58012b65585SGordon Ross case LSA_MTYPE_ES_CONT:
58112b65585SGordon Ross case LSA_MTYPE_ES_DONE:
58212b65585SGordon Ross default:
58312b65585SGordon Ross return (-1);
58412b65585SGordon Ross }
58512b65585SGordon Ross
5866926de2eSGordon Ross if (rc == NT_STATUS_NO_MEMORY)
5876926de2eSGordon Ross smbd_nomem();
5886926de2eSGordon Ross
58912b65585SGordon Ross if (rc != 0) {
59012b65585SGordon Ross smb_lsa_eresp_t *er = ctx->ctx_orawbuf;
59112b65585SGordon Ross ctx->ctx_orawtype = LSA_MTYPE_ERROR;
59212b65585SGordon Ross ctx->ctx_orawlen = sizeof (*er);
59312b65585SGordon Ross er->ler_ntstatus = rc;
59412b65585SGordon Ross er->ler_errclass = 0;
59512b65585SGordon Ross er->ler_errcode = 0;
59612b65585SGordon Ross }
59712b65585SGordon Ross return (0);
59812b65585SGordon Ross }
59912b65585SGordon Ross
60012b65585SGordon Ross static int
smbd_authsvc_oldreq(authsvc_context_t * ctx)60112b65585SGordon Ross smbd_authsvc_oldreq(authsvc_context_t *ctx)
60212b65585SGordon Ross {
60312b65585SGordon Ross smb_logon_t user_info;
60412b65585SGordon Ross XDR xdrs;
60512b65585SGordon Ross smb_token_t *token = NULL;
60612b65585SGordon Ross int rc = 0;
60712b65585SGordon Ross
60812b65585SGordon Ross bzero(&user_info, sizeof (user_info));
60912b65585SGordon Ross xdrmem_create(&xdrs, ctx->ctx_irawbuf, ctx->ctx_irawlen,
61012b65585SGordon Ross XDR_DECODE);
61112b65585SGordon Ross if (!smb_logon_xdr(&xdrs, &user_info)) {
61212b65585SGordon Ross xdr_destroy(&xdrs);
61312b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER);
61412b65585SGordon Ross }
61512b65585SGordon Ross xdr_destroy(&xdrs);
61612b65585SGordon Ross
61712b65585SGordon Ross token = smbd_user_auth_logon(&user_info);
61812b65585SGordon Ross xdr_free(smb_logon_xdr, (char *)&user_info);
619975041ddSGordon Ross if (token == NULL) {
620975041ddSGordon Ross rc = user_info.lg_status;
621975041ddSGordon Ross if (rc == 0) /* should not happen */
622975041ddSGordon Ross rc = NT_STATUS_INTERNAL_ERROR;
623975041ddSGordon Ross return (rc);
624975041ddSGordon Ross }
62512b65585SGordon Ross
62612b65585SGordon Ross ctx->ctx_token = token;
62712b65585SGordon Ross
62812b65585SGordon Ross return (rc);
62912b65585SGordon Ross }
63012b65585SGordon Ross
63112b65585SGordon Ross static int
smbd_authsvc_clinfo(authsvc_context_t * ctx)63212b65585SGordon Ross smbd_authsvc_clinfo(authsvc_context_t *ctx)
63312b65585SGordon Ross {
63412b65585SGordon Ross
63512b65585SGordon Ross if (ctx->ctx_irawlen != sizeof (smb_lsa_clinfo_t))
63612b65585SGordon Ross return (NT_STATUS_INTERNAL_ERROR);
63712b65585SGordon Ross (void) memcpy(&ctx->ctx_clinfo, ctx->ctx_irawbuf,
63812b65585SGordon Ross sizeof (smb_lsa_clinfo_t));
63912b65585SGordon Ross
64012b65585SGordon Ross ctx->ctx_orawtype = LSA_MTYPE_OK;
64112b65585SGordon Ross ctx->ctx_orawlen = 0;
64212b65585SGordon Ross return (0);
64312b65585SGordon Ross }
64412b65585SGordon Ross
64512b65585SGordon Ross /*
64612b65585SGordon Ross * Handle a security blob we've received from the client.
64712b65585SGordon Ross * Incoming type: LSA_MTYPE_ESFIRST
64812b65585SGordon Ross * Outgoing types: LSA_MTYPE_ES_CONT, LSA_MTYPE_ES_DONE,
64912b65585SGordon Ross * LSA_MTYPE_ERROR
65012b65585SGordon Ross */
65112b65585SGordon Ross static int
smbd_authsvc_esfirst(authsvc_context_t * ctx)65212b65585SGordon Ross smbd_authsvc_esfirst(authsvc_context_t *ctx)
65312b65585SGordon Ross {
65412b65585SGordon Ross const spnego_mech_handler_t *mh;
65512b65585SGordon Ross int idx, pref, rc;
65612b65585SGordon Ross int best_pref = 1000;
65712b65585SGordon Ross int best_mhidx = -1;
65812b65585SGordon Ross
65912b65585SGordon Ross /*
66012b65585SGordon Ross * NTLMSSP header is 8+, SPNEGO is 10+
66112b65585SGordon Ross */
66212b65585SGordon Ross if (ctx->ctx_irawlen < 8) {
66312b65585SGordon Ross smbd_report("authsvc: short blob");
66412b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER);
66512b65585SGordon Ross }
66612b65585SGordon Ross
66712b65585SGordon Ross /*
66812b65585SGordon Ross * We could have "Raw NTLMSSP" here intead of SPNEGO.
66912b65585SGordon Ross */
67012b65585SGordon Ross if (bcmp(ctx->ctx_irawbuf, "NTLMSSP", 8) == 0) {
67112b65585SGordon Ross rc = smbd_raw_ntlmssp_esfirst(ctx);
67212b65585SGordon Ross return (rc);
67312b65585SGordon Ross }
67412b65585SGordon Ross
67512b65585SGordon Ross /*
67612b65585SGordon Ross * Parse the SPNEGO token, check its type.
67712b65585SGordon Ross */
67812b65585SGordon Ross rc = spnegoInitFromBinary(ctx->ctx_irawbuf,
67912b65585SGordon Ross ctx->ctx_irawlen, &ctx->ctx_itoken);
68012b65585SGordon Ross if (rc != 0) {
68112b65585SGordon Ross smbd_report("authsvc: spnego parse failed");
68212b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER);
68312b65585SGordon Ross }
68412b65585SGordon Ross
68512b65585SGordon Ross rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype);
68612b65585SGordon Ross if (rc != 0) {
68712b65585SGordon Ross smbd_report("authsvc: spnego get token type failed");
68812b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER);
68912b65585SGordon Ross }
69012b65585SGordon Ross
69112b65585SGordon Ross if (ctx->ctx_itoktype != SPNEGO_TOKEN_INIT) {
69212b65585SGordon Ross smbd_report("authsvc: spnego wrong token type %d",
69312b65585SGordon Ross ctx->ctx_itoktype);
69412b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER);
69512b65585SGordon Ross }
69612b65585SGordon Ross
69712b65585SGordon Ross /*
69812b65585SGordon Ross * Figure out which mech type to use. We want to use the
69912b65585SGordon Ross * first of the client's supported mechanisms that we also
70012b65585SGordon Ross * support. Unfortunately, the spnego code does not have an
70112b65585SGordon Ross * interface to walk the token's mech list, so we have to
70212b65585SGordon Ross * ask about each mech type we know and keep track of which
70312b65585SGordon Ross * was earliest in the token's mech list.
70412b65585SGordon Ross *
70512b65585SGordon Ross * Also, skip the Kerberos mechanisms in workgroup mode.
70612b65585SGordon Ross */
70712b65585SGordon Ross idx = 0;
70812b65585SGordon Ross mh = mech_table;
70912b65585SGordon Ross if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) {
71012b65585SGordon Ross idx = MECH_TBL_IDX_NTLMSSP;
71112b65585SGordon Ross mh = &mech_table[idx];
71212b65585SGordon Ross }
71312b65585SGordon Ross for (; mh->mh_init != NULL; idx++, mh++) {
71412b65585SGordon Ross
71512b65585SGordon Ross if (spnegoIsMechTypeAvailable(ctx->ctx_itoken,
71612b65585SGordon Ross mh->mh_oid, &pref) != 0)
71712b65585SGordon Ross continue;
71812b65585SGordon Ross
71912b65585SGordon Ross if (pref < best_pref) {
72012b65585SGordon Ross best_pref = pref;
72112b65585SGordon Ross best_mhidx = idx;
72212b65585SGordon Ross }
72312b65585SGordon Ross }
72412b65585SGordon Ross if (best_mhidx == -1) {
72512b65585SGordon Ross smbd_report("authsvc: no supported spnego mechanism");
72612b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER);
72712b65585SGordon Ross }
72812b65585SGordon Ross
72912b65585SGordon Ross /* Found a mutually agreeable mech. */
73012b65585SGordon Ross mh = &mech_table[best_mhidx];
73112b65585SGordon Ross ctx->ctx_mech_oid = mh->mh_oid;
73212b65585SGordon Ross ctx->ctx_mh_work = mh->mh_work;
73312b65585SGordon Ross ctx->ctx_mh_fini = mh->mh_fini;
73412b65585SGordon Ross rc = mh->mh_init(ctx);
73512b65585SGordon Ross if (rc != 0) {
73612b65585SGordon Ross smbd_report("authsvc: mech init failed");
73712b65585SGordon Ross return (rc);
73812b65585SGordon Ross }
73912b65585SGordon Ross
74012b65585SGordon Ross /*
741cc86afeeSGordon Ross * If the best supported mech was not the first in the list,
742cc86afeeSGordon Ross * we need to ask the client to use a different one, and
743cc86afeeSGordon Ross * skip (ignore) the provided token body.
74412b65585SGordon Ross */
745cc86afeeSGordon Ross if (best_pref != 0) {
746cc86afeeSGordon Ross rc = smbd_authsvc_newmech(ctx);
747cc86afeeSGordon Ross } else {
748cc86afeeSGordon Ross /*
749cc86afeeSGordon Ross * Common to LSA_MTYPE_ESFIRST, LSA_MTYPE_ESNEXT
750cc86afeeSGordon Ross */
751cc86afeeSGordon Ross rc = smbd_authsvc_escmn(ctx);
752cc86afeeSGordon Ross }
75312b65585SGordon Ross return (rc);
75412b65585SGordon Ross }
75512b65585SGordon Ross
75612b65585SGordon Ross /*
75712b65585SGordon Ross * Handle a security blob we've received from the client.
75812b65585SGordon Ross * Incoming type: LSA_MTYPE_ESNEXT
75912b65585SGordon Ross * Outgoing types: LSA_MTYPE_ES_CONT, LSA_MTYPE_ES_DONE,
76012b65585SGordon Ross * LSA_MTYPE_ERROR
76112b65585SGordon Ross */
76212b65585SGordon Ross static int
smbd_authsvc_esnext(authsvc_context_t * ctx)76312b65585SGordon Ross smbd_authsvc_esnext(authsvc_context_t *ctx)
76412b65585SGordon Ross {
76512b65585SGordon Ross int rc;
76612b65585SGordon Ross
76712b65585SGordon Ross /*
76812b65585SGordon Ross * Make sure LSA_MTYPE_ESFIRST was handled
76912b65585SGordon Ross * previously, so we have a work function.
77012b65585SGordon Ross */
77112b65585SGordon Ross if (ctx->ctx_mh_work == NULL)
77212b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER);
77312b65585SGordon Ross
77412b65585SGordon Ross if (ctx->ctx_mech_oid == special_mech_raw_NTLMSSP) {
77512b65585SGordon Ross rc = smbd_raw_ntlmssp_esnext(ctx);
77612b65585SGordon Ross return (rc);
77712b65585SGordon Ross }
77812b65585SGordon Ross
77912b65585SGordon Ross /*
78012b65585SGordon Ross * Cleanup state from previous calls.
78112b65585SGordon Ross */
78212b65585SGordon Ross if (ctx->ctx_itoken != NULL) {
78312b65585SGordon Ross spnegoFreeData(ctx->ctx_itoken);
78412b65585SGordon Ross ctx->ctx_itoken = NULL;
78512b65585SGordon Ross }
78612b65585SGordon Ross
78712b65585SGordon Ross /*
78812b65585SGordon Ross * Parse the SPNEGO token, check its type.
78912b65585SGordon Ross */
79012b65585SGordon Ross rc = spnegoInitFromBinary(ctx->ctx_irawbuf,
79112b65585SGordon Ross ctx->ctx_irawlen, &ctx->ctx_itoken);
79212b65585SGordon Ross if (rc != 0)
79312b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER);
79412b65585SGordon Ross
79512b65585SGordon Ross rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype);
79612b65585SGordon Ross if (rc != 0)
79712b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER);
79812b65585SGordon Ross
79912b65585SGordon Ross if (ctx->ctx_itoktype != SPNEGO_TOKEN_TARG)
80012b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER);
80112b65585SGordon Ross
80212b65585SGordon Ross rc = smbd_authsvc_escmn(ctx);
80312b65585SGordon Ross return (rc);
80412b65585SGordon Ross }
80512b65585SGordon Ross
80612b65585SGordon Ross static int
smbd_authsvc_escmn(authsvc_context_t * ctx)80712b65585SGordon Ross smbd_authsvc_escmn(authsvc_context_t *ctx)
80812b65585SGordon Ross {
80912b65585SGordon Ross SPNEGO_MECH_OID oid;
81012b65585SGordon Ross ulong_t toklen;
81112b65585SGordon Ross int rc;
81212b65585SGordon Ross
81312b65585SGordon Ross /*
81412b65585SGordon Ross * Cleanup state from previous calls.
81512b65585SGordon Ross */
81612b65585SGordon Ross if (ctx->ctx_otoken != NULL) {
81712b65585SGordon Ross spnegoFreeData(ctx->ctx_otoken);
81812b65585SGordon Ross ctx->ctx_otoken = NULL;
81912b65585SGordon Ross }
82012b65585SGordon Ross
82112b65585SGordon Ross /*
82212b65585SGordon Ross * Extract the payload (mech token).
82312b65585SGordon Ross */
82412b65585SGordon Ross toklen = ctx->ctx_ibodylen;
82512b65585SGordon Ross rc = spnegoGetMechToken(ctx->ctx_itoken,
82612b65585SGordon Ross ctx->ctx_ibodybuf, &toklen);
82712b65585SGordon Ross switch (rc) {
82812b65585SGordon Ross case SPNEGO_E_SUCCESS:
82912b65585SGordon Ross break;
83012b65585SGordon Ross case SPNEGO_E_ELEMENT_UNAVAILABLE:
83112b65585SGordon Ross toklen = 0;
83212b65585SGordon Ross break;
83312b65585SGordon Ross case SPNEGO_E_BUFFER_TOO_SMALL:
83412b65585SGordon Ross return (NT_STATUS_BUFFER_TOO_SMALL);
83512b65585SGordon Ross default:
83612b65585SGordon Ross return (NT_STATUS_INTERNAL_ERROR);
83712b65585SGordon Ross }
83812b65585SGordon Ross ctx->ctx_ibodylen = toklen;
83912b65585SGordon Ross
84012b65585SGordon Ross /*
84112b65585SGordon Ross * Now that we have the incoming "body" (mech. token),
84212b65585SGordon Ross * call the back-end mech-specific work function to
84312b65585SGordon Ross * create the outgoing "body" (mech. token).
84412b65585SGordon Ross *
84512b65585SGordon Ross * The worker must fill in: ctx->ctx_negresult,
84612b65585SGordon Ross * and: ctx->ctx_obodylen, but ctx->ctx_obodybuf
84712b65585SGordon Ross * is optional, and is typically NULL after the
84812b65585SGordon Ross * final message of an auth sequence, where
84912b65585SGordon Ross * negresult == spnego_negresult_complete.
85012b65585SGordon Ross */
85112b65585SGordon Ross rc = ctx->ctx_mh_work(ctx);
85212b65585SGordon Ross if (rc != 0)
85312b65585SGordon Ross return (rc);
85412b65585SGordon Ross
85512b65585SGordon Ross /*
85612b65585SGordon Ross * Wrap the outgoing body in a negTokenTarg SPNEGO token.
85712b65585SGordon Ross * The selected mech. OID is returned only when the
85812b65585SGordon Ross * incoming token was of type SPNEGO_TOKEN_INIT.
85912b65585SGordon Ross */
86012b65585SGordon Ross if (ctx->ctx_itoktype == SPNEGO_TOKEN_INIT) {
86112b65585SGordon Ross /* tell the client the selected mech. */
86212b65585SGordon Ross oid = ctx->ctx_mech_oid;
86312b65585SGordon Ross } else {
864a44e7c2cSGordon Ross /* Omit the "supported mech." field. */
86512b65585SGordon Ross oid = spnego_mech_oid_NotUsed;
86612b65585SGordon Ross }
86712b65585SGordon Ross
86812b65585SGordon Ross /*
86912b65585SGordon Ross * Determine the spnego "negresult" from the
87012b65585SGordon Ross * reply message type (from the work func).
87112b65585SGordon Ross */
87212b65585SGordon Ross switch (ctx->ctx_orawtype) {
87312b65585SGordon Ross case LSA_MTYPE_ERROR:
87412b65585SGordon Ross ctx->ctx_negresult = spnego_negresult_rejected;
87512b65585SGordon Ross break;
87612b65585SGordon Ross case LSA_MTYPE_ES_DONE:
87712b65585SGordon Ross ctx->ctx_negresult = spnego_negresult_success;
87812b65585SGordon Ross break;
87912b65585SGordon Ross case LSA_MTYPE_ES_CONT:
88012b65585SGordon Ross ctx->ctx_negresult = spnego_negresult_incomplete;
88112b65585SGordon Ross break;
88212b65585SGordon Ross default:
88312b65585SGordon Ross return (-1);
88412b65585SGordon Ross }
88512b65585SGordon Ross
88612b65585SGordon Ross rc = spnegoCreateNegTokenTarg(
88712b65585SGordon Ross oid,
88812b65585SGordon Ross ctx->ctx_negresult,
88912b65585SGordon Ross ctx->ctx_obodybuf, /* may be NULL */
89012b65585SGordon Ross ctx->ctx_obodylen,
89112b65585SGordon Ross NULL, 0,
89212b65585SGordon Ross &ctx->ctx_otoken);
893cc86afeeSGordon Ross if (rc != 0)
894cc86afeeSGordon Ross return (NT_STATUS_INTERNAL_ERROR);
895cc86afeeSGordon Ross
896cc86afeeSGordon Ross /*
897cc86afeeSGordon Ross * Convert the SPNEGO token into binary form,
898cc86afeeSGordon Ross * writing it to the output buffer.
899cc86afeeSGordon Ross */
900cc86afeeSGordon Ross toklen = smbd_authsvc_bufsize;
901cc86afeeSGordon Ross rc = spnegoTokenGetBinary(ctx->ctx_otoken,
902cc86afeeSGordon Ross (uchar_t *)ctx->ctx_orawbuf, &toklen);
903cc86afeeSGordon Ross if (rc != 0)
904cc86afeeSGordon Ross rc = NT_STATUS_INTERNAL_ERROR;
905cc86afeeSGordon Ross ctx->ctx_orawlen = (uint_t)toklen;
906cc86afeeSGordon Ross
907cc86afeeSGordon Ross return (rc);
908cc86afeeSGordon Ross }
909cc86afeeSGordon Ross
910cc86afeeSGordon Ross /*
911cc86afeeSGordon Ross * The first NegTokenInit we receive, handled in smbd_authsvc_esfirst,
912cc86afeeSGordon Ross * contains a list of supported mechanisms, in order from the client's
913cc86afeeSGordon Ross * most preferred to least preferred. The token also contains a body
914cc86afeeSGordon Ross * for the first mechanism listed, which is used immediately if the
915cc86afeeSGordon Ross * first mechanism is mutually agreeable. If the first mechanism is
916cc86afeeSGordon Ross * not supported on our side, we must "propose a new mechanism" from
917cc86afeeSGordon Ross * the list. Our caller has selected a mech and initialized the ctx
918cc86afeeSGordon Ross * mech functions. Here compose a reply with an empty body and the
919cc86afeeSGordon Ross * proposed new mechanism OID. The token body received is for some
920cc86afeeSGordon Ross * other mech, so we skip calling the work function with that token.
921cc86afeeSGordon Ross *
922cc86afeeSGordon Ross * Just send a NegTokenTarg with an empty body and the OID for the
923cc86afeeSGordon Ross * proposed mechanism. The next message should be the real first
924cc86afeeSGordon Ross * token for this mechanism, handled in smbd_authsvc_exnext.
925cc86afeeSGordon Ross */
926cc86afeeSGordon Ross static int
smbd_authsvc_newmech(authsvc_context_t * ctx)927cc86afeeSGordon Ross smbd_authsvc_newmech(authsvc_context_t *ctx)
928cc86afeeSGordon Ross {
929cc86afeeSGordon Ross ulong_t toklen;
930cc86afeeSGordon Ross int rc;
931cc86afeeSGordon Ross
932cc86afeeSGordon Ross /*
933cc86afeeSGordon Ross * Don't call mh_work here.
934cc86afeeSGordon Ross * Just tell the clint the selected mech.
935cc86afeeSGordon Ross */
936cc86afeeSGordon Ross ctx->ctx_ibodylen = 0;
937cc86afeeSGordon Ross ctx->ctx_orawtype = LSA_MTYPE_ES_CONT;
938cc86afeeSGordon Ross ctx->ctx_obodylen = 0;
939cc86afeeSGordon Ross ctx->ctx_negresult = spnego_negresult_request_mic;
940cc86afeeSGordon Ross
941cc86afeeSGordon Ross rc = spnegoCreateNegTokenTarg(
942cc86afeeSGordon Ross ctx->ctx_mech_oid,
943cc86afeeSGordon Ross ctx->ctx_negresult,
944cc86afeeSGordon Ross NULL, 0,
945cc86afeeSGordon Ross NULL, 0,
946cc86afeeSGordon Ross &ctx->ctx_otoken);
947cc86afeeSGordon Ross if (rc != 0)
948cc86afeeSGordon Ross return (NT_STATUS_INTERNAL_ERROR);
94912b65585SGordon Ross
95012b65585SGordon Ross /*
95112b65585SGordon Ross * Convert the SPNEGO token into binary form,
95212b65585SGordon Ross * writing it to the output buffer.
95312b65585SGordon Ross */
95412b65585SGordon Ross toklen = smbd_authsvc_bufsize;
95512b65585SGordon Ross rc = spnegoTokenGetBinary(ctx->ctx_otoken,
95612b65585SGordon Ross (uchar_t *)ctx->ctx_orawbuf, &toklen);
95712b65585SGordon Ross if (rc)
95812b65585SGordon Ross rc = NT_STATUS_INTERNAL_ERROR;
95912b65585SGordon Ross ctx->ctx_orawlen = (uint_t)toklen;
96012b65585SGordon Ross
96112b65585SGordon Ross return (rc);
96212b65585SGordon Ross }
96312b65585SGordon Ross
96412b65585SGordon Ross /*
96512b65585SGordon Ross * Wrapper for "Raw NTLMSSP", which is exactly like the
96612b65585SGordon Ross * normal (SPNEGO-wrapped) NTLMSSP but without SPNEGO.
96712b65585SGordon Ross * Setup back-end handler for: special_mech_raw_NTLMSSP
96812b65585SGordon Ross * Compare with smbd_authsvc_esfirst().
96912b65585SGordon Ross */
97012b65585SGordon Ross static int
smbd_raw_ntlmssp_esfirst(authsvc_context_t * ctx)97112b65585SGordon Ross smbd_raw_ntlmssp_esfirst(authsvc_context_t *ctx)
97212b65585SGordon Ross {
97312b65585SGordon Ross const spnego_mech_handler_t *mh;
97412b65585SGordon Ross int rc;
97512b65585SGordon Ross
97612b65585SGordon Ross mh = &smbd_auth_mech_raw_ntlmssp;
97712b65585SGordon Ross rc = mh->mh_init(ctx);
97812b65585SGordon Ross if (rc != 0)
97912b65585SGordon Ross return (rc);
98012b65585SGordon Ross
98112b65585SGordon Ross ctx->ctx_mech_oid = mh->mh_oid;
98212b65585SGordon Ross ctx->ctx_mh_work = mh->mh_work;
98312b65585SGordon Ross ctx->ctx_mh_fini = mh->mh_fini;
98412b65585SGordon Ross
98512b65585SGordon Ross rc = smbd_raw_ntlmssp_esnext(ctx);
98612b65585SGordon Ross
98712b65585SGordon Ross return (rc);
98812b65585SGordon Ross }
98912b65585SGordon Ross
99012b65585SGordon Ross
99112b65585SGordon Ross /*
99212b65585SGordon Ross * Wrapper for "Raw NTLMSSP", which is exactly like the
99312b65585SGordon Ross * normal (SPNEGO-wrapped) NTLMSSP but without SPNEGO.
99412b65585SGordon Ross * Just copy "raw" to "body", and vice versa.
99512b65585SGordon Ross * Compare with smbd_authsvc_esnext, smbd_authsvc_escmn
99612b65585SGordon Ross */
99712b65585SGordon Ross static int
smbd_raw_ntlmssp_esnext(authsvc_context_t * ctx)99812b65585SGordon Ross smbd_raw_ntlmssp_esnext(authsvc_context_t *ctx)
99912b65585SGordon Ross {
100012b65585SGordon Ross int rc;
100112b65585SGordon Ross
100212b65585SGordon Ross ctx->ctx_ibodylen = ctx->ctx_irawlen;
100312b65585SGordon Ross (void) memcpy(ctx->ctx_ibodybuf,
100412b65585SGordon Ross ctx->ctx_irawbuf, ctx->ctx_irawlen);
100512b65585SGordon Ross
100612b65585SGordon Ross rc = ctx->ctx_mh_work(ctx);
100712b65585SGordon Ross
100812b65585SGordon Ross ctx->ctx_orawlen = ctx->ctx_obodylen;
100912b65585SGordon Ross (void) memcpy(ctx->ctx_orawbuf,
101012b65585SGordon Ross ctx->ctx_obodybuf, ctx->ctx_obodylen);
101112b65585SGordon Ross
101212b65585SGordon Ross return (rc);
101312b65585SGordon Ross }
101412b65585SGordon Ross
101512b65585SGordon Ross
101612b65585SGordon Ross /*
101712b65585SGordon Ross * After a successful authentication, request the access token.
101812b65585SGordon Ross */
101912b65585SGordon Ross static int
smbd_authsvc_gettoken(authsvc_context_t * ctx)102012b65585SGordon Ross smbd_authsvc_gettoken(authsvc_context_t *ctx)
102112b65585SGordon Ross {
102212b65585SGordon Ross XDR xdrs;
102312b65585SGordon Ross smb_token_t *token = NULL;
102412b65585SGordon Ross int rc = 0;
102512b65585SGordon Ross int len;
102612b65585SGordon Ross
102712b65585SGordon Ross if ((token = ctx->ctx_token) == NULL)
102812b65585SGordon Ross return (NT_STATUS_ACCESS_DENIED);
102912b65585SGordon Ross
103012b65585SGordon Ross /*
103112b65585SGordon Ross * Encode the token response
103212b65585SGordon Ross */
103312b65585SGordon Ross len = xdr_sizeof(smb_token_xdr, token);
103412b65585SGordon Ross if (len > ctx->ctx_orawlen) {
103512b65585SGordon Ross if ((ctx->ctx_orawbuf = realloc(ctx->ctx_orawbuf, len)) ==
103612b65585SGordon Ross NULL) {
10376926de2eSGordon Ross return (NT_STATUS_NO_MEMORY);
103812b65585SGordon Ross }
103912b65585SGordon Ross }
104012b65585SGordon Ross
104112b65585SGordon Ross ctx->ctx_orawtype = LSA_MTYPE_TOKEN;
104212b65585SGordon Ross ctx->ctx_orawlen = len;
104312b65585SGordon Ross xdrmem_create(&xdrs, ctx->ctx_orawbuf, len, XDR_ENCODE);
104412b65585SGordon Ross if (!smb_token_xdr(&xdrs, token))
104512b65585SGordon Ross rc = NT_STATUS_INTERNAL_ERROR;
104612b65585SGordon Ross xdr_destroy(&xdrs);
104712b65585SGordon Ross
104812b65585SGordon Ross return (rc);
104912b65585SGordon Ross }
105012b65585SGordon Ross
105112b65585SGordon Ross /*
105212b65585SGordon Ross * Initialization time code to figure out what mechanisms we support.
105312b65585SGordon Ross * Careful with this table; the code below knows its format and may
1054a44e7c2cSGordon Ross * skip the fist two entries to omit Kerberos.
105512b65585SGordon Ross */
105612b65585SGordon Ross static SPNEGO_MECH_OID MechTypeList[] = {
105712b65585SGordon Ross spnego_mech_oid_Kerberos_V5,
105812b65585SGordon Ross spnego_mech_oid_Kerberos_V5_Legacy,
105912b65585SGordon Ross #define MECH_OID_IDX_NTLMSSP 2
106012b65585SGordon Ross spnego_mech_oid_NTLMSSP,
106112b65585SGordon Ross };
106212b65585SGordon Ross static int MechTypeCnt = sizeof (MechTypeList) /
106312b65585SGordon Ross sizeof (MechTypeList[0]);
106412b65585SGordon Ross
106512b65585SGordon Ross /* This string is just like Windows. */
106612b65585SGordon Ross static char IgnoreSPN[] = "not_defined_in_RFC4178@please_ignore";
106712b65585SGordon Ross
106812b65585SGordon Ross /*
106912b65585SGordon Ross * Build the SPNEGO "hint" token based on the
107012b65585SGordon Ross * configured authentication mechanisms.
107112b65585SGordon Ross * (NTLMSSP, and maybe Kerberos)
107212b65585SGordon Ross */
107312b65585SGordon Ross void
smbd_get_authconf(smb_kmod_cfg_t * kcfg)107412b65585SGordon Ross smbd_get_authconf(smb_kmod_cfg_t *kcfg)
107512b65585SGordon Ross {
107612b65585SGordon Ross SPNEGO_MECH_OID *mechList = MechTypeList;
107712b65585SGordon Ross int mechCnt = MechTypeCnt;
107812b65585SGordon Ross SPNEGO_TOKEN_HANDLE hSpnegoToken = NULL;
107912b65585SGordon Ross uchar_t *pBuf = kcfg->skc_negtok;
108012b65585SGordon Ross uint32_t *pBufLen = &kcfg->skc_negtok_len;
108112b65585SGordon Ross ulong_t tLen = sizeof (kcfg->skc_negtok);
108212b65585SGordon Ross int rc;
108312b65585SGordon Ross
108412b65585SGordon Ross /*
108512b65585SGordon Ross * In workgroup mode, skip Kerberos.
108612b65585SGordon Ross */
108712b65585SGordon Ross if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) {
108812b65585SGordon Ross mechList += MECH_OID_IDX_NTLMSSP;
108912b65585SGordon Ross mechCnt -= MECH_OID_IDX_NTLMSSP;
109012b65585SGordon Ross }
109112b65585SGordon Ross
109212b65585SGordon Ross rc = spnegoCreateNegTokenHint(mechList, mechCnt,
109312b65585SGordon Ross (uchar_t *)IgnoreSPN, &hSpnegoToken);
109412b65585SGordon Ross if (rc != SPNEGO_E_SUCCESS) {
109512b65585SGordon Ross syslog(LOG_DEBUG, "smb_config_get_negtok: "
109612b65585SGordon Ross "spnegoCreateNegTokenHint, rc=%d", rc);
109712b65585SGordon Ross *pBufLen = 0;
109812b65585SGordon Ross return;
109912b65585SGordon Ross }
110012b65585SGordon Ross rc = spnegoTokenGetBinary(hSpnegoToken, pBuf, &tLen);
110112b65585SGordon Ross if (rc != SPNEGO_E_SUCCESS) {
110212b65585SGordon Ross syslog(LOG_DEBUG, "smb_config_get_negtok: "
110312b65585SGordon Ross "spnegoTokenGetBinary, rc=%d", rc);
110412b65585SGordon Ross *pBufLen = 0;
110512b65585SGordon Ross } else {
110612b65585SGordon Ross *pBufLen = (uint32_t)tLen;
110712b65585SGordon Ross }
110812b65585SGordon Ross spnegoFreeData(hSpnegoToken);
110912b65585SGordon Ross }
1110