1*12b65585SGordon Ross /* 2*12b65585SGordon Ross * This file and its contents are supplied under the terms of the 3*12b65585SGordon Ross * Common Development and Distribution License ("CDDL"), version 1.0. 4*12b65585SGordon Ross * You may only use this file in accordance with the terms of version 5*12b65585SGordon Ross * 1.0 of the CDDL. 6*12b65585SGordon Ross * 7*12b65585SGordon Ross * A full copy of the text of the CDDL should have accompanied this 8*12b65585SGordon Ross * source. A copy of the CDDL is also available via the Internet at 9*12b65585SGordon Ross * http://www.illumos.org/license/CDDL. 10*12b65585SGordon Ross */ 11*12b65585SGordon Ross 12*12b65585SGordon Ross /* 13*12b65585SGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 14*12b65585SGordon Ross */ 15*12b65585SGordon Ross 16*12b65585SGordon Ross /* 17*12b65585SGordon Ross * SMB authentication service 18*12b65585SGordon Ross * 19*12b65585SGordon Ross * This service listens on a local AF_UNIX socket, spawning a 20*12b65585SGordon Ross * thread to service each connection. The client-side of such 21*12b65585SGordon Ross * connections is the in-kernel SMB service, with an open and 22*12b65585SGordon Ross * connect done in the SMB session setup handler. 23*12b65585SGordon Ross */ 24*12b65585SGordon Ross 25*12b65585SGordon Ross #include <sys/types.h> 26*12b65585SGordon Ross #include <stdlib.h> 27*12b65585SGordon Ross #include <errno.h> 28*12b65585SGordon Ross #include <string.h> 29*12b65585SGordon Ross #include <strings.h> 30*12b65585SGordon Ross #include <unistd.h> 31*12b65585SGordon Ross #include <signal.h> 32*12b65585SGordon Ross #include <stdio.h> 33*12b65585SGordon Ross #include <note.h> 34*12b65585SGordon Ross #include <net/if.h> 35*12b65585SGordon Ross #include <net/route.h> 36*12b65585SGordon Ross #include <sys/sockio.h> 37*12b65585SGordon Ross #include <sys/socket.h> 38*12b65585SGordon Ross #include <sys/un.h> 39*12b65585SGordon Ross #include <netinet/in.h> 40*12b65585SGordon Ross #include <fcntl.h> 41*12b65585SGordon Ross #include <pthread.h> 42*12b65585SGordon Ross #include <syslog.h> 43*12b65585SGordon Ross #include <smbsrv/libsmb.h> 44*12b65585SGordon Ross #include <netsmb/spnego.h> 45*12b65585SGordon Ross 46*12b65585SGordon Ross #include "smbd.h" 47*12b65585SGordon Ross #include "smbd_authsvc.h" 48*12b65585SGordon Ross 49*12b65585SGordon Ross /* Arbitrary value outside the (small) range of valid OIDs */ 50*12b65585SGordon Ross #define special_mech_raw_NTLMSSP (spnego_mech_oid_NTLMSSP + 100) 51*12b65585SGordon Ross 52*12b65585SGordon Ross static struct sockaddr_un smbauth_sockname = { 53*12b65585SGordon Ross AF_UNIX, SMB_AUTHSVC_SOCKNAME }; 54*12b65585SGordon Ross 55*12b65585SGordon Ross typedef struct spnego_mech_handler { 56*12b65585SGordon Ross int mh_oid; /* SPNEGO_MECH_OID */ 57*12b65585SGordon Ross int (*mh_init)(authsvc_context_t *); 58*12b65585SGordon Ross int (*mh_work)(authsvc_context_t *); 59*12b65585SGordon Ross void (*mh_fini)(authsvc_context_t *); 60*12b65585SGordon Ross } spnego_mech_handler_t; 61*12b65585SGordon Ross 62*12b65585SGordon Ross static int smbd_authsock_create(void); 63*12b65585SGordon Ross static void smbd_authsock_destroy(void); 64*12b65585SGordon Ross static void *smbd_authsvc_listen(void *); 65*12b65585SGordon Ross static void *smbd_authsvc_work(void *); 66*12b65585SGordon Ross static void smbd_authsvc_flood(void); 67*12b65585SGordon Ross 68*12b65585SGordon Ross static int smbd_authsvc_oldreq(authsvc_context_t *); 69*12b65585SGordon Ross static int smbd_authsvc_clinfo(authsvc_context_t *); 70*12b65585SGordon Ross static int smbd_authsvc_esfirst(authsvc_context_t *); 71*12b65585SGordon Ross static int smbd_authsvc_esnext(authsvc_context_t *); 72*12b65585SGordon Ross static int smbd_authsvc_escmn(authsvc_context_t *); 73*12b65585SGordon Ross static int smbd_authsvc_gettoken(authsvc_context_t *); 74*12b65585SGordon Ross static int smbd_raw_ntlmssp_esfirst(authsvc_context_t *); 75*12b65585SGordon Ross static int smbd_raw_ntlmssp_esnext(authsvc_context_t *); 76*12b65585SGordon Ross 77*12b65585SGordon Ross /* 78*12b65585SGordon Ross * We can get relatively large tokens now, thanks to krb5 PAC. 79*12b65585SGordon Ross * Might be better to size these buffers dynamically, but these 80*12b65585SGordon Ross * are all short-lived so not bothering with that for now. 81*12b65585SGordon Ross */ 82*12b65585SGordon Ross int smbd_authsvc_bufsize = 65000; 83*12b65585SGordon Ross 84*12b65585SGordon Ross static mutex_t smbd_authsvc_mutex = DEFAULTMUTEX; 85*12b65585SGordon Ross 86*12b65585SGordon Ross /* 87*12b65585SGordon Ross * The maximum number of authentication thread is limited by the 88*12b65585SGordon Ross * smbsrv smb_threshold_...(->sv_ssetup_ct) mechanism. However, 89*12b65585SGordon Ross * due to occasional delays closing these auth. sockets, we need 90*12b65585SGordon Ross * a little "slack" on the number of threads we'll allow, as 91*12b65585SGordon Ross * compared with the in-kernel limit. We could perhaps just 92*12b65585SGordon Ross * remove this limit now, but want it for extra safety. 93*12b65585SGordon Ross */ 94*12b65585SGordon Ross int smbd_authsvc_maxthread = SMB_AUTHSVC_MAXTHREAD + 32; 95*12b65585SGordon Ross int smbd_authsvc_thrcnt = 0; /* current thrcnt */ 96*12b65585SGordon Ross int smbd_authsvc_hiwat = 0; /* largest thrcnt seen */ 97*12b65585SGordon Ross #ifdef DEBUG 98*12b65585SGordon Ross int smbd_authsvc_slowdown = 0; 99*12b65585SGordon Ross #endif 100*12b65585SGordon Ross 101*12b65585SGordon Ross /* 102*12b65585SGordon Ross * These are the mechanisms we support, in order of preference. 103*12b65585SGordon Ross * But note: it's really the _client's_ preference that matters. 104*12b65585SGordon Ross * See &pref in the spnegoIsMechTypeAvailable() calls below. 105*12b65585SGordon Ross * Careful with this table; the code below knows its format and 106*12b65585SGordon Ross * may skip the fist two entries to ommit Kerberos. 107*12b65585SGordon Ross */ 108*12b65585SGordon Ross static const spnego_mech_handler_t 109*12b65585SGordon Ross mech_table[] = { 110*12b65585SGordon Ross { 111*12b65585SGordon Ross spnego_mech_oid_Kerberos_V5, 112*12b65585SGordon Ross smbd_krb5ssp_init, 113*12b65585SGordon Ross smbd_krb5ssp_work, 114*12b65585SGordon Ross smbd_krb5ssp_fini 115*12b65585SGordon Ross }, 116*12b65585SGordon Ross { 117*12b65585SGordon Ross spnego_mech_oid_Kerberos_V5_Legacy, 118*12b65585SGordon Ross smbd_krb5ssp_init, 119*12b65585SGordon Ross smbd_krb5ssp_work, 120*12b65585SGordon Ross smbd_krb5ssp_fini 121*12b65585SGordon Ross }, 122*12b65585SGordon Ross #define MECH_TBL_IDX_NTLMSSP 2 123*12b65585SGordon Ross { 124*12b65585SGordon Ross spnego_mech_oid_NTLMSSP, 125*12b65585SGordon Ross smbd_ntlmssp_init, 126*12b65585SGordon Ross smbd_ntlmssp_work, 127*12b65585SGordon Ross smbd_ntlmssp_fini 128*12b65585SGordon Ross }, 129*12b65585SGordon Ross { 130*12b65585SGordon Ross /* end marker */ 131*12b65585SGordon Ross spnego_mech_oid_NotUsed, 132*12b65585SGordon Ross NULL, NULL, NULL 133*12b65585SGordon Ross }, 134*12b65585SGordon Ross }; 135*12b65585SGordon Ross 136*12b65585SGordon Ross static const spnego_mech_handler_t 137*12b65585SGordon Ross smbd_auth_mech_raw_ntlmssp = { 138*12b65585SGordon Ross special_mech_raw_NTLMSSP, 139*12b65585SGordon Ross smbd_ntlmssp_init, 140*12b65585SGordon Ross smbd_ntlmssp_work, 141*12b65585SGordon Ross smbd_ntlmssp_fini 142*12b65585SGordon Ross }; 143*12b65585SGordon Ross 144*12b65585SGordon Ross 145*12b65585SGordon Ross /* 146*12b65585SGordon Ross * Start the authentication service. 147*12b65585SGordon Ross * Returns non-zero on error. 148*12b65585SGordon Ross */ 149*12b65585SGordon Ross int 150*12b65585SGordon Ross smbd_authsvc_start(void) 151*12b65585SGordon Ross { 152*12b65585SGordon Ross pthread_attr_t attr; 153*12b65585SGordon Ross pthread_t tid; 154*12b65585SGordon Ross int rc; 155*12b65585SGordon Ross 156*12b65585SGordon Ross rc = smbd_authsock_create(); 157*12b65585SGordon Ross if (rc) 158*12b65585SGordon Ross return (rc); 159*12b65585SGordon Ross 160*12b65585SGordon Ross (void) pthread_attr_init(&attr); 161*12b65585SGordon Ross (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 162*12b65585SGordon Ross rc = pthread_create(&tid, &attr, smbd_authsvc_listen, &smbd); 163*12b65585SGordon Ross (void) pthread_attr_destroy(&attr); 164*12b65585SGordon Ross if (rc) { 165*12b65585SGordon Ross smbd_authsock_destroy(); 166*12b65585SGordon Ross return (rc); 167*12b65585SGordon Ross } 168*12b65585SGordon Ross 169*12b65585SGordon Ross smbd.s_authsvc_tid = tid; 170*12b65585SGordon Ross return (0); 171*12b65585SGordon Ross } 172*12b65585SGordon Ross 173*12b65585SGordon Ross void 174*12b65585SGordon Ross smbd_authsvc_stop(void) 175*12b65585SGordon Ross { 176*12b65585SGordon Ross 177*12b65585SGordon Ross if (smbd.s_authsvc_tid != 0) { 178*12b65585SGordon Ross (void) pthread_kill(smbd.s_authsvc_tid, SIGTERM); 179*12b65585SGordon Ross smbd.s_authsvc_tid = 0; 180*12b65585SGordon Ross } 181*12b65585SGordon Ross } 182*12b65585SGordon Ross 183*12b65585SGordon Ross static int 184*12b65585SGordon Ross smbd_authsock_create(void) 185*12b65585SGordon Ross { 186*12b65585SGordon Ross int sock = -1; 187*12b65585SGordon Ross 188*12b65585SGordon Ross sock = socket(AF_UNIX, SOCK_STREAM, 0); 189*12b65585SGordon Ross if (sock < 0) { 190*12b65585SGordon Ross smbd_report("authsvc, socket create failed, %d", errno); 191*12b65585SGordon Ross return (errno); 192*12b65585SGordon Ross } 193*12b65585SGordon Ross 194*12b65585SGordon Ross (void) unlink(smbauth_sockname.sun_path); 195*12b65585SGordon Ross if (bind(sock, (struct sockaddr *)&smbauth_sockname, 196*12b65585SGordon Ross sizeof (smbauth_sockname)) < 0) { 197*12b65585SGordon Ross smbd_report("authsvc, socket bind failed, %d", errno); 198*12b65585SGordon Ross (void) close(sock); 199*12b65585SGordon Ross return (errno); 200*12b65585SGordon Ross } 201*12b65585SGordon Ross 202*12b65585SGordon Ross if (listen(sock, SOMAXCONN) < 0) { 203*12b65585SGordon Ross smbd_report("authsvc, socket listen failed, %d", errno); 204*12b65585SGordon Ross (void) close(sock); 205*12b65585SGordon Ross return (errno); 206*12b65585SGordon Ross } 207*12b65585SGordon Ross 208*12b65585SGordon Ross smbd.s_authsvc_sock = sock; 209*12b65585SGordon Ross return (0); 210*12b65585SGordon Ross } 211*12b65585SGordon Ross 212*12b65585SGordon Ross static void 213*12b65585SGordon Ross smbd_authsock_destroy(void) 214*12b65585SGordon Ross { 215*12b65585SGordon Ross int fid; 216*12b65585SGordon Ross 217*12b65585SGordon Ross if ((fid = smbd.s_authsvc_sock) != -1) { 218*12b65585SGordon Ross smbd.s_authsvc_sock = -1; 219*12b65585SGordon Ross (void) close(fid); 220*12b65585SGordon Ross } 221*12b65585SGordon Ross } 222*12b65585SGordon Ross 223*12b65585SGordon Ross static void * 224*12b65585SGordon Ross smbd_authsvc_listen(void *arg) 225*12b65585SGordon Ross { 226*12b65585SGordon Ross authsvc_context_t *ctx; 227*12b65585SGordon Ross pthread_attr_t attr; 228*12b65585SGordon Ross pthread_t tid; 229*12b65585SGordon Ross socklen_t slen; 230*12b65585SGordon Ross int ls, ns, rc; 231*12b65585SGordon Ross 232*12b65585SGordon Ross _NOTE(ARGUNUSED(arg)) 233*12b65585SGordon Ross 234*12b65585SGordon Ross (void) pthread_attr_init(&attr); 235*12b65585SGordon Ross (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 236*12b65585SGordon Ross 237*12b65585SGordon Ross ls = smbd.s_authsvc_sock; 238*12b65585SGordon Ross for (;;) { 239*12b65585SGordon Ross 240*12b65585SGordon Ross slen = 0; 241*12b65585SGordon Ross ns = accept(ls, NULL, &slen); 242*12b65585SGordon Ross if (ns < 0) { 243*12b65585SGordon Ross switch (errno) { 244*12b65585SGordon Ross case ECONNABORTED: 245*12b65585SGordon Ross continue; 246*12b65585SGordon Ross case EINTR: 247*12b65585SGordon Ross /* normal termination */ 248*12b65585SGordon Ross goto out; 249*12b65585SGordon Ross default: 250*12b65585SGordon Ross smbd_report("authsvc, socket accept failed," 251*12b65585SGordon Ross " %d", errno); 252*12b65585SGordon Ross goto out; 253*12b65585SGordon Ross } 254*12b65585SGordon Ross } 255*12b65585SGordon Ross 256*12b65585SGordon Ross /* 257*12b65585SGordon Ross * Limit the number of auth. sockets 258*12b65585SGordon Ross * (and the threads that service them). 259*12b65585SGordon Ross */ 260*12b65585SGordon Ross (void) mutex_lock(&smbd_authsvc_mutex); 261*12b65585SGordon Ross if (smbd_authsvc_thrcnt >= smbd_authsvc_maxthread) { 262*12b65585SGordon Ross (void) mutex_unlock(&smbd_authsvc_mutex); 263*12b65585SGordon Ross (void) close(ns); 264*12b65585SGordon Ross smbd_authsvc_flood(); 265*12b65585SGordon Ross continue; 266*12b65585SGordon Ross } 267*12b65585SGordon Ross smbd_authsvc_thrcnt++; 268*12b65585SGordon Ross if (smbd_authsvc_hiwat < smbd_authsvc_thrcnt) 269*12b65585SGordon Ross smbd_authsvc_hiwat = smbd_authsvc_thrcnt; 270*12b65585SGordon Ross (void) mutex_unlock(&smbd_authsvc_mutex); 271*12b65585SGordon Ross 272*12b65585SGordon Ross ctx = smbd_authctx_create(); 273*12b65585SGordon Ross if (ctx == NULL) { 274*12b65585SGordon Ross smbd_report("authsvc, can't allocate context"); 275*12b65585SGordon Ross (void) mutex_lock(&smbd_authsvc_mutex); 276*12b65585SGordon Ross smbd_authsvc_thrcnt--; 277*12b65585SGordon Ross (void) mutex_unlock(&smbd_authsvc_mutex); 278*12b65585SGordon Ross (void) close(ns); 279*12b65585SGordon Ross goto out; 280*12b65585SGordon Ross } 281*12b65585SGordon Ross ctx->ctx_socket = ns; 282*12b65585SGordon Ross 283*12b65585SGordon Ross rc = pthread_create(&tid, &attr, smbd_authsvc_work, ctx); 284*12b65585SGordon Ross if (rc) { 285*12b65585SGordon Ross smbd_report("authsvc, thread create failed, %d", rc); 286*12b65585SGordon Ross (void) mutex_lock(&smbd_authsvc_mutex); 287*12b65585SGordon Ross smbd_authsvc_thrcnt--; 288*12b65585SGordon Ross (void) mutex_unlock(&smbd_authsvc_mutex); 289*12b65585SGordon Ross smbd_authctx_destroy(ctx); 290*12b65585SGordon Ross goto out; 291*12b65585SGordon Ross } 292*12b65585SGordon Ross ctx = NULL; /* given to the new thread */ 293*12b65585SGordon Ross } 294*12b65585SGordon Ross 295*12b65585SGordon Ross out: 296*12b65585SGordon Ross (void) pthread_attr_destroy(&attr); 297*12b65585SGordon Ross smbd_authsock_destroy(); 298*12b65585SGordon Ross return (NULL); 299*12b65585SGordon Ross } 300*12b65585SGordon Ross 301*12b65585SGordon Ross static void 302*12b65585SGordon Ross smbd_authsvc_flood(void) 303*12b65585SGordon Ross { 304*12b65585SGordon Ross static uint_t count; 305*12b65585SGordon Ross static time_t last_report; 306*12b65585SGordon Ross time_t now = time(NULL); 307*12b65585SGordon Ross 308*12b65585SGordon Ross count++; 309*12b65585SGordon Ross if (last_report + 60 < now) { 310*12b65585SGordon Ross last_report = now; 311*12b65585SGordon Ross smbd_report("authsvc: flooded %u", count); 312*12b65585SGordon Ross count = 0; 313*12b65585SGordon Ross } 314*12b65585SGordon Ross } 315*12b65585SGordon Ross 316*12b65585SGordon Ross authsvc_context_t * 317*12b65585SGordon Ross smbd_authctx_create(void) 318*12b65585SGordon Ross { 319*12b65585SGordon Ross authsvc_context_t *ctx; 320*12b65585SGordon Ross 321*12b65585SGordon Ross ctx = malloc(sizeof (*ctx)); 322*12b65585SGordon Ross if (ctx == NULL) 323*12b65585SGordon Ross return (NULL); 324*12b65585SGordon Ross bzero(ctx, sizeof (*ctx)); 325*12b65585SGordon Ross 326*12b65585SGordon Ross ctx->ctx_irawlen = smbd_authsvc_bufsize; 327*12b65585SGordon Ross ctx->ctx_irawbuf = malloc(ctx->ctx_irawlen); 328*12b65585SGordon Ross ctx->ctx_orawlen = smbd_authsvc_bufsize; 329*12b65585SGordon Ross ctx->ctx_orawbuf = malloc(ctx->ctx_orawlen); 330*12b65585SGordon Ross if (ctx->ctx_irawbuf == NULL || ctx->ctx_orawbuf == NULL) 331*12b65585SGordon Ross goto errout; 332*12b65585SGordon Ross 333*12b65585SGordon Ross ctx->ctx_ibodylen = smbd_authsvc_bufsize; 334*12b65585SGordon Ross ctx->ctx_ibodybuf = malloc(ctx->ctx_ibodylen); 335*12b65585SGordon Ross ctx->ctx_obodylen = smbd_authsvc_bufsize; 336*12b65585SGordon Ross ctx->ctx_obodybuf = malloc(ctx->ctx_obodylen); 337*12b65585SGordon Ross if (ctx->ctx_ibodybuf == NULL || ctx->ctx_obodybuf == NULL) 338*12b65585SGordon Ross goto errout; 339*12b65585SGordon Ross 340*12b65585SGordon Ross return (ctx); 341*12b65585SGordon Ross 342*12b65585SGordon Ross errout: 343*12b65585SGordon Ross smbd_authctx_destroy(ctx); 344*12b65585SGordon Ross return (NULL); 345*12b65585SGordon Ross } 346*12b65585SGordon Ross 347*12b65585SGordon Ross void 348*12b65585SGordon Ross smbd_authctx_destroy(authsvc_context_t *ctx) 349*12b65585SGordon Ross { 350*12b65585SGordon Ross if (ctx->ctx_socket != -1) { 351*12b65585SGordon Ross (void) close(ctx->ctx_socket); 352*12b65585SGordon Ross ctx->ctx_socket = -1; 353*12b65585SGordon Ross } 354*12b65585SGordon Ross 355*12b65585SGordon Ross if (ctx->ctx_token != NULL) 356*12b65585SGordon Ross smb_token_destroy(ctx->ctx_token); 357*12b65585SGordon Ross 358*12b65585SGordon Ross if (ctx->ctx_itoken != NULL) 359*12b65585SGordon Ross spnegoFreeData(ctx->ctx_itoken); 360*12b65585SGordon Ross if (ctx->ctx_otoken != NULL) 361*12b65585SGordon Ross spnegoFreeData(ctx->ctx_otoken); 362*12b65585SGordon Ross 363*12b65585SGordon Ross free(ctx->ctx_irawbuf); 364*12b65585SGordon Ross free(ctx->ctx_orawbuf); 365*12b65585SGordon Ross free(ctx->ctx_ibodybuf); 366*12b65585SGordon Ross free(ctx->ctx_obodybuf); 367*12b65585SGordon Ross 368*12b65585SGordon Ross free(ctx); 369*12b65585SGordon Ross } 370*12b65585SGordon Ross 371*12b65585SGordon Ross /* 372*12b65585SGordon Ross * Limit how long smbd_authsvc_work will wait for the client to 373*12b65585SGordon Ross * send us the next part of the authentication sequence. 374*12b65585SGordon Ross */ 375*12b65585SGordon Ross static struct timeval recv_tmo = { 30, 0 }; 376*12b65585SGordon Ross 377*12b65585SGordon Ross /* 378*12b65585SGordon Ross * Also set a timeout for send, where we're sending a response to 379*12b65585SGordon Ross * the client side (in smbsrv). That should always be waiting in 380*12b65585SGordon Ross * recv by the time we send, so a short timeout is OK. 381*12b65585SGordon Ross */ 382*12b65585SGordon Ross static struct timeval send_tmo = { 15, 0 }; 383*12b65585SGordon Ross 384*12b65585SGordon Ross static void * 385*12b65585SGordon Ross smbd_authsvc_work(void *arg) 386*12b65585SGordon Ross { 387*12b65585SGordon Ross authsvc_context_t *ctx = arg; 388*12b65585SGordon Ross smb_lsa_msg_hdr_t hdr; 389*12b65585SGordon Ross int sock = ctx->ctx_socket; 390*12b65585SGordon Ross int len, rc; 391*12b65585SGordon Ross 392*12b65585SGordon Ross if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, 393*12b65585SGordon Ross (char *)&send_tmo, sizeof (send_tmo)) != 0) { 394*12b65585SGordon Ross smbd_report("authsvc_work: set set timeout: %m"); 395*12b65585SGordon Ross goto out; 396*12b65585SGordon Ross } 397*12b65585SGordon Ross 398*12b65585SGordon Ross if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, 399*12b65585SGordon Ross (char *)&recv_tmo, sizeof (recv_tmo)) != 0) { 400*12b65585SGordon Ross smbd_report("authsvc_work: set recv timeout: %m"); 401*12b65585SGordon Ross goto out; 402*12b65585SGordon Ross } 403*12b65585SGordon Ross 404*12b65585SGordon Ross for (;;) { 405*12b65585SGordon Ross 406*12b65585SGordon Ross len = recv(sock, &hdr, sizeof (hdr), MSG_WAITALL); 407*12b65585SGordon Ross if (len <= 0) { 408*12b65585SGordon Ross /* normal termination */ 409*12b65585SGordon Ross break; 410*12b65585SGordon Ross } 411*12b65585SGordon Ross if (len != sizeof (hdr)) { 412*12b65585SGordon Ross smbd_report("authsvc_work: read header failed"); 413*12b65585SGordon Ross break; 414*12b65585SGordon Ross } 415*12b65585SGordon Ross 416*12b65585SGordon Ross if (hdr.lmh_msglen > smbd_authsvc_bufsize) { 417*12b65585SGordon Ross smbd_report("authsvc_work: msg too large"); 418*12b65585SGordon Ross break; 419*12b65585SGordon Ross } 420*12b65585SGordon Ross 421*12b65585SGordon Ross if (hdr.lmh_msglen > 0) { 422*12b65585SGordon Ross len = recv(sock, ctx->ctx_irawbuf, hdr.lmh_msglen, 423*12b65585SGordon Ross MSG_WAITALL); 424*12b65585SGordon Ross if (len != hdr.lmh_msglen) { 425*12b65585SGordon Ross smbd_report("authsvc_work: read mesg failed"); 426*12b65585SGordon Ross break; 427*12b65585SGordon Ross } 428*12b65585SGordon Ross } 429*12b65585SGordon Ross ctx->ctx_irawtype = hdr.lmh_msgtype; 430*12b65585SGordon Ross ctx->ctx_irawlen = hdr.lmh_msglen; 431*12b65585SGordon Ross ctx->ctx_orawlen = smbd_authsvc_bufsize; 432*12b65585SGordon Ross ctx->ctx_ibodylen = smbd_authsvc_bufsize; 433*12b65585SGordon Ross ctx->ctx_obodylen = smbd_authsvc_bufsize; 434*12b65585SGordon Ross 435*12b65585SGordon Ross /* 436*12b65585SGordon Ross * The real work happens here. 437*12b65585SGordon Ross */ 438*12b65585SGordon Ross rc = smbd_authsvc_dispatch(ctx); 439*12b65585SGordon Ross if (rc) 440*12b65585SGordon Ross break; 441*12b65585SGordon Ross 442*12b65585SGordon Ross hdr.lmh_msgtype = ctx->ctx_orawtype; 443*12b65585SGordon Ross hdr.lmh_msglen = ctx->ctx_orawlen; 444*12b65585SGordon Ross len = send(sock, &hdr, sizeof (hdr), 0); 445*12b65585SGordon Ross if (len != sizeof (hdr)) { 446*12b65585SGordon Ross smbd_report("authsvc_work: send failed"); 447*12b65585SGordon Ross break; 448*12b65585SGordon Ross } 449*12b65585SGordon Ross 450*12b65585SGordon Ross if (ctx->ctx_orawlen > 0) { 451*12b65585SGordon Ross len = send(sock, ctx->ctx_orawbuf, 452*12b65585SGordon Ross ctx->ctx_orawlen, 0); 453*12b65585SGordon Ross if (len != ctx->ctx_orawlen) { 454*12b65585SGordon Ross smbd_report("authsvc_work: send failed"); 455*12b65585SGordon Ross break; 456*12b65585SGordon Ross } 457*12b65585SGordon Ross } 458*12b65585SGordon Ross } 459*12b65585SGordon Ross 460*12b65585SGordon Ross out: 461*12b65585SGordon Ross if (ctx->ctx_mh_fini) 462*12b65585SGordon Ross (ctx->ctx_mh_fini)(ctx); 463*12b65585SGordon Ross 464*12b65585SGordon Ross smbd_authctx_destroy(ctx); 465*12b65585SGordon Ross 466*12b65585SGordon Ross (void) mutex_lock(&smbd_authsvc_mutex); 467*12b65585SGordon Ross smbd_authsvc_thrcnt--; 468*12b65585SGordon Ross (void) mutex_unlock(&smbd_authsvc_mutex); 469*12b65585SGordon Ross 470*12b65585SGordon Ross return (NULL); /* implied pthread_exit() */ 471*12b65585SGordon Ross } 472*12b65585SGordon Ross 473*12b65585SGordon Ross /* 474*12b65585SGordon Ross * Dispatch based on message type LSA_MTYPE_... 475*12b65585SGordon Ross * Non-zero return here ends the conversation. 476*12b65585SGordon Ross */ 477*12b65585SGordon Ross int 478*12b65585SGordon Ross smbd_authsvc_dispatch(authsvc_context_t *ctx) 479*12b65585SGordon Ross { 480*12b65585SGordon Ross int rc; 481*12b65585SGordon Ross 482*12b65585SGordon Ross switch (ctx->ctx_irawtype) { 483*12b65585SGordon Ross 484*12b65585SGordon Ross case LSA_MTYPE_OLDREQ: 485*12b65585SGordon Ross #ifdef DEBUG 486*12b65585SGordon Ross if (smbd_authsvc_slowdown) 487*12b65585SGordon Ross (void) sleep(smbd_authsvc_slowdown); 488*12b65585SGordon Ross #endif 489*12b65585SGordon Ross rc = smbd_authsvc_oldreq(ctx); 490*12b65585SGordon Ross break; 491*12b65585SGordon Ross 492*12b65585SGordon Ross case LSA_MTYPE_CLINFO: 493*12b65585SGordon Ross rc = smbd_authsvc_clinfo(ctx); 494*12b65585SGordon Ross break; 495*12b65585SGordon Ross 496*12b65585SGordon Ross case LSA_MTYPE_ESFIRST: 497*12b65585SGordon Ross rc = smbd_authsvc_esfirst(ctx); 498*12b65585SGordon Ross break; 499*12b65585SGordon Ross 500*12b65585SGordon Ross case LSA_MTYPE_ESNEXT: 501*12b65585SGordon Ross #ifdef DEBUG 502*12b65585SGordon Ross if (smbd_authsvc_slowdown) 503*12b65585SGordon Ross (void) sleep(smbd_authsvc_slowdown); 504*12b65585SGordon Ross #endif 505*12b65585SGordon Ross rc = smbd_authsvc_esnext(ctx); 506*12b65585SGordon Ross break; 507*12b65585SGordon Ross 508*12b65585SGordon Ross case LSA_MTYPE_GETTOK: 509*12b65585SGordon Ross rc = smbd_authsvc_gettoken(ctx); 510*12b65585SGordon Ross break; 511*12b65585SGordon Ross 512*12b65585SGordon Ross /* response types */ 513*12b65585SGordon Ross case LSA_MTYPE_OK: 514*12b65585SGordon Ross case LSA_MTYPE_ERROR: 515*12b65585SGordon Ross case LSA_MTYPE_TOKEN: 516*12b65585SGordon Ross case LSA_MTYPE_ES_CONT: 517*12b65585SGordon Ross case LSA_MTYPE_ES_DONE: 518*12b65585SGordon Ross default: 519*12b65585SGordon Ross return (-1); 520*12b65585SGordon Ross } 521*12b65585SGordon Ross 522*12b65585SGordon Ross if (rc != 0) { 523*12b65585SGordon Ross smb_lsa_eresp_t *er = ctx->ctx_orawbuf; 524*12b65585SGordon Ross ctx->ctx_orawtype = LSA_MTYPE_ERROR; 525*12b65585SGordon Ross ctx->ctx_orawlen = sizeof (*er); 526*12b65585SGordon Ross er->ler_ntstatus = rc; 527*12b65585SGordon Ross er->ler_errclass = 0; 528*12b65585SGordon Ross er->ler_errcode = 0; 529*12b65585SGordon Ross } 530*12b65585SGordon Ross return (0); 531*12b65585SGordon Ross } 532*12b65585SGordon Ross 533*12b65585SGordon Ross static int 534*12b65585SGordon Ross smbd_authsvc_oldreq(authsvc_context_t *ctx) 535*12b65585SGordon Ross { 536*12b65585SGordon Ross smb_logon_t user_info; 537*12b65585SGordon Ross XDR xdrs; 538*12b65585SGordon Ross smb_token_t *token = NULL; 539*12b65585SGordon Ross int rc = 0; 540*12b65585SGordon Ross 541*12b65585SGordon Ross bzero(&user_info, sizeof (user_info)); 542*12b65585SGordon Ross xdrmem_create(&xdrs, ctx->ctx_irawbuf, ctx->ctx_irawlen, 543*12b65585SGordon Ross XDR_DECODE); 544*12b65585SGordon Ross if (!smb_logon_xdr(&xdrs, &user_info)) { 545*12b65585SGordon Ross xdr_destroy(&xdrs); 546*12b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER); 547*12b65585SGordon Ross } 548*12b65585SGordon Ross xdr_destroy(&xdrs); 549*12b65585SGordon Ross 550*12b65585SGordon Ross token = smbd_user_auth_logon(&user_info); 551*12b65585SGordon Ross xdr_free(smb_logon_xdr, (char *)&user_info); 552*12b65585SGordon Ross if (token == NULL) 553*12b65585SGordon Ross return (NT_STATUS_ACCESS_DENIED); 554*12b65585SGordon Ross 555*12b65585SGordon Ross ctx->ctx_token = token; 556*12b65585SGordon Ross 557*12b65585SGordon Ross return (rc); 558*12b65585SGordon Ross } 559*12b65585SGordon Ross 560*12b65585SGordon Ross static int 561*12b65585SGordon Ross smbd_authsvc_clinfo(authsvc_context_t *ctx) 562*12b65585SGordon Ross { 563*12b65585SGordon Ross 564*12b65585SGordon Ross if (ctx->ctx_irawlen != sizeof (smb_lsa_clinfo_t)) 565*12b65585SGordon Ross return (NT_STATUS_INTERNAL_ERROR); 566*12b65585SGordon Ross (void) memcpy(&ctx->ctx_clinfo, ctx->ctx_irawbuf, 567*12b65585SGordon Ross sizeof (smb_lsa_clinfo_t)); 568*12b65585SGordon Ross 569*12b65585SGordon Ross ctx->ctx_orawtype = LSA_MTYPE_OK; 570*12b65585SGordon Ross ctx->ctx_orawlen = 0; 571*12b65585SGordon Ross return (0); 572*12b65585SGordon Ross } 573*12b65585SGordon Ross 574*12b65585SGordon Ross /* 575*12b65585SGordon Ross * Handle a security blob we've received from the client. 576*12b65585SGordon Ross * Incoming type: LSA_MTYPE_ESFIRST 577*12b65585SGordon Ross * Outgoing types: LSA_MTYPE_ES_CONT, LSA_MTYPE_ES_DONE, 578*12b65585SGordon Ross * LSA_MTYPE_ERROR 579*12b65585SGordon Ross */ 580*12b65585SGordon Ross static int 581*12b65585SGordon Ross smbd_authsvc_esfirst(authsvc_context_t *ctx) 582*12b65585SGordon Ross { 583*12b65585SGordon Ross const spnego_mech_handler_t *mh; 584*12b65585SGordon Ross int idx, pref, rc; 585*12b65585SGordon Ross int best_pref = 1000; 586*12b65585SGordon Ross int best_mhidx = -1; 587*12b65585SGordon Ross 588*12b65585SGordon Ross /* 589*12b65585SGordon Ross * NTLMSSP header is 8+, SPNEGO is 10+ 590*12b65585SGordon Ross */ 591*12b65585SGordon Ross if (ctx->ctx_irawlen < 8) { 592*12b65585SGordon Ross smbd_report("authsvc: short blob"); 593*12b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER); 594*12b65585SGordon Ross } 595*12b65585SGordon Ross 596*12b65585SGordon Ross /* 597*12b65585SGordon Ross * We could have "Raw NTLMSSP" here intead of SPNEGO. 598*12b65585SGordon Ross */ 599*12b65585SGordon Ross if (bcmp(ctx->ctx_irawbuf, "NTLMSSP", 8) == 0) { 600*12b65585SGordon Ross rc = smbd_raw_ntlmssp_esfirst(ctx); 601*12b65585SGordon Ross return (rc); 602*12b65585SGordon Ross } 603*12b65585SGordon Ross 604*12b65585SGordon Ross /* 605*12b65585SGordon Ross * Parse the SPNEGO token, check its type. 606*12b65585SGordon Ross */ 607*12b65585SGordon Ross rc = spnegoInitFromBinary(ctx->ctx_irawbuf, 608*12b65585SGordon Ross ctx->ctx_irawlen, &ctx->ctx_itoken); 609*12b65585SGordon Ross if (rc != 0) { 610*12b65585SGordon Ross smbd_report("authsvc: spnego parse failed"); 611*12b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER); 612*12b65585SGordon Ross } 613*12b65585SGordon Ross 614*12b65585SGordon Ross rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype); 615*12b65585SGordon Ross if (rc != 0) { 616*12b65585SGordon Ross smbd_report("authsvc: spnego get token type failed"); 617*12b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER); 618*12b65585SGordon Ross } 619*12b65585SGordon Ross 620*12b65585SGordon Ross if (ctx->ctx_itoktype != SPNEGO_TOKEN_INIT) { 621*12b65585SGordon Ross smbd_report("authsvc: spnego wrong token type %d", 622*12b65585SGordon Ross ctx->ctx_itoktype); 623*12b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER); 624*12b65585SGordon Ross } 625*12b65585SGordon Ross 626*12b65585SGordon Ross /* 627*12b65585SGordon Ross * Figure out which mech type to use. We want to use the 628*12b65585SGordon Ross * first of the client's supported mechanisms that we also 629*12b65585SGordon Ross * support. Unfortunately, the spnego code does not have an 630*12b65585SGordon Ross * interface to walk the token's mech list, so we have to 631*12b65585SGordon Ross * ask about each mech type we know and keep track of which 632*12b65585SGordon Ross * was earliest in the token's mech list. 633*12b65585SGordon Ross * 634*12b65585SGordon Ross * Also, skip the Kerberos mechanisms in workgroup mode. 635*12b65585SGordon Ross */ 636*12b65585SGordon Ross idx = 0; 637*12b65585SGordon Ross mh = mech_table; 638*12b65585SGordon Ross if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) { 639*12b65585SGordon Ross idx = MECH_TBL_IDX_NTLMSSP; 640*12b65585SGordon Ross mh = &mech_table[idx]; 641*12b65585SGordon Ross } 642*12b65585SGordon Ross for (; mh->mh_init != NULL; idx++, mh++) { 643*12b65585SGordon Ross 644*12b65585SGordon Ross if (spnegoIsMechTypeAvailable(ctx->ctx_itoken, 645*12b65585SGordon Ross mh->mh_oid, &pref) != 0) 646*12b65585SGordon Ross continue; 647*12b65585SGordon Ross 648*12b65585SGordon Ross if (pref < best_pref) { 649*12b65585SGordon Ross best_pref = pref; 650*12b65585SGordon Ross best_mhidx = idx; 651*12b65585SGordon Ross } 652*12b65585SGordon Ross } 653*12b65585SGordon Ross if (best_mhidx == -1) { 654*12b65585SGordon Ross smbd_report("authsvc: no supported spnego mechanism"); 655*12b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER); 656*12b65585SGordon Ross } 657*12b65585SGordon Ross 658*12b65585SGordon Ross /* Found a mutually agreeable mech. */ 659*12b65585SGordon Ross mh = &mech_table[best_mhidx]; 660*12b65585SGordon Ross ctx->ctx_mech_oid = mh->mh_oid; 661*12b65585SGordon Ross ctx->ctx_mh_work = mh->mh_work; 662*12b65585SGordon Ross ctx->ctx_mh_fini = mh->mh_fini; 663*12b65585SGordon Ross rc = mh->mh_init(ctx); 664*12b65585SGordon Ross if (rc != 0) { 665*12b65585SGordon Ross smbd_report("authsvc: mech init failed"); 666*12b65585SGordon Ross return (rc); 667*12b65585SGordon Ross } 668*12b65585SGordon Ross 669*12b65585SGordon Ross /* 670*12b65585SGordon Ross * Common to LSA_MTYPE_ESFIRST, LSA_MTYPE_ESNEXT 671*12b65585SGordon Ross */ 672*12b65585SGordon Ross rc = smbd_authsvc_escmn(ctx); 673*12b65585SGordon Ross return (rc); 674*12b65585SGordon Ross } 675*12b65585SGordon Ross 676*12b65585SGordon Ross /* 677*12b65585SGordon Ross * Handle a security blob we've received from the client. 678*12b65585SGordon Ross * Incoming type: LSA_MTYPE_ESNEXT 679*12b65585SGordon Ross * Outgoing types: LSA_MTYPE_ES_CONT, LSA_MTYPE_ES_DONE, 680*12b65585SGordon Ross * LSA_MTYPE_ERROR 681*12b65585SGordon Ross */ 682*12b65585SGordon Ross static int 683*12b65585SGordon Ross smbd_authsvc_esnext(authsvc_context_t *ctx) 684*12b65585SGordon Ross { 685*12b65585SGordon Ross int rc; 686*12b65585SGordon Ross 687*12b65585SGordon Ross /* 688*12b65585SGordon Ross * Make sure LSA_MTYPE_ESFIRST was handled 689*12b65585SGordon Ross * previously, so we have a work function. 690*12b65585SGordon Ross */ 691*12b65585SGordon Ross if (ctx->ctx_mh_work == NULL) 692*12b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER); 693*12b65585SGordon Ross 694*12b65585SGordon Ross if (ctx->ctx_mech_oid == special_mech_raw_NTLMSSP) { 695*12b65585SGordon Ross rc = smbd_raw_ntlmssp_esnext(ctx); 696*12b65585SGordon Ross return (rc); 697*12b65585SGordon Ross } 698*12b65585SGordon Ross 699*12b65585SGordon Ross /* 700*12b65585SGordon Ross * Cleanup state from previous calls. 701*12b65585SGordon Ross */ 702*12b65585SGordon Ross if (ctx->ctx_itoken != NULL) { 703*12b65585SGordon Ross spnegoFreeData(ctx->ctx_itoken); 704*12b65585SGordon Ross ctx->ctx_itoken = NULL; 705*12b65585SGordon Ross } 706*12b65585SGordon Ross 707*12b65585SGordon Ross /* 708*12b65585SGordon Ross * Parse the SPNEGO token, check its type. 709*12b65585SGordon Ross */ 710*12b65585SGordon Ross rc = spnegoInitFromBinary(ctx->ctx_irawbuf, 711*12b65585SGordon Ross ctx->ctx_irawlen, &ctx->ctx_itoken); 712*12b65585SGordon Ross if (rc != 0) 713*12b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER); 714*12b65585SGordon Ross 715*12b65585SGordon Ross rc = spnegoGetTokenType(ctx->ctx_itoken, &ctx->ctx_itoktype); 716*12b65585SGordon Ross if (rc != 0) 717*12b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER); 718*12b65585SGordon Ross 719*12b65585SGordon Ross if (ctx->ctx_itoktype != SPNEGO_TOKEN_TARG) 720*12b65585SGordon Ross return (NT_STATUS_INVALID_PARAMETER); 721*12b65585SGordon Ross 722*12b65585SGordon Ross rc = smbd_authsvc_escmn(ctx); 723*12b65585SGordon Ross return (rc); 724*12b65585SGordon Ross } 725*12b65585SGordon Ross 726*12b65585SGordon Ross static int 727*12b65585SGordon Ross smbd_authsvc_escmn(authsvc_context_t *ctx) 728*12b65585SGordon Ross { 729*12b65585SGordon Ross SPNEGO_MECH_OID oid; 730*12b65585SGordon Ross ulong_t toklen; 731*12b65585SGordon Ross int rc; 732*12b65585SGordon Ross 733*12b65585SGordon Ross /* 734*12b65585SGordon Ross * Cleanup state from previous calls. 735*12b65585SGordon Ross */ 736*12b65585SGordon Ross if (ctx->ctx_otoken != NULL) { 737*12b65585SGordon Ross spnegoFreeData(ctx->ctx_otoken); 738*12b65585SGordon Ross ctx->ctx_otoken = NULL; 739*12b65585SGordon Ross } 740*12b65585SGordon Ross 741*12b65585SGordon Ross /* 742*12b65585SGordon Ross * Extract the payload (mech token). 743*12b65585SGordon Ross */ 744*12b65585SGordon Ross toklen = ctx->ctx_ibodylen; 745*12b65585SGordon Ross rc = spnegoGetMechToken(ctx->ctx_itoken, 746*12b65585SGordon Ross ctx->ctx_ibodybuf, &toklen); 747*12b65585SGordon Ross switch (rc) { 748*12b65585SGordon Ross case SPNEGO_E_SUCCESS: 749*12b65585SGordon Ross break; 750*12b65585SGordon Ross case SPNEGO_E_ELEMENT_UNAVAILABLE: 751*12b65585SGordon Ross toklen = 0; 752*12b65585SGordon Ross break; 753*12b65585SGordon Ross case SPNEGO_E_BUFFER_TOO_SMALL: 754*12b65585SGordon Ross return (NT_STATUS_BUFFER_TOO_SMALL); 755*12b65585SGordon Ross default: 756*12b65585SGordon Ross return (NT_STATUS_INTERNAL_ERROR); 757*12b65585SGordon Ross } 758*12b65585SGordon Ross ctx->ctx_ibodylen = toklen; 759*12b65585SGordon Ross 760*12b65585SGordon Ross /* 761*12b65585SGordon Ross * Now that we have the incoming "body" (mech. token), 762*12b65585SGordon Ross * call the back-end mech-specific work function to 763*12b65585SGordon Ross * create the outgoing "body" (mech. token). 764*12b65585SGordon Ross * 765*12b65585SGordon Ross * The worker must fill in: ctx->ctx_negresult, 766*12b65585SGordon Ross * and: ctx->ctx_obodylen, but ctx->ctx_obodybuf 767*12b65585SGordon Ross * is optional, and is typically NULL after the 768*12b65585SGordon Ross * final message of an auth sequence, where 769*12b65585SGordon Ross * negresult == spnego_negresult_complete. 770*12b65585SGordon Ross */ 771*12b65585SGordon Ross rc = ctx->ctx_mh_work(ctx); 772*12b65585SGordon Ross if (rc != 0) 773*12b65585SGordon Ross return (rc); 774*12b65585SGordon Ross 775*12b65585SGordon Ross /* 776*12b65585SGordon Ross * Wrap the outgoing body in a negTokenTarg SPNEGO token. 777*12b65585SGordon Ross * The selected mech. OID is returned only when the 778*12b65585SGordon Ross * incoming token was of type SPNEGO_TOKEN_INIT. 779*12b65585SGordon Ross */ 780*12b65585SGordon Ross if (ctx->ctx_itoktype == SPNEGO_TOKEN_INIT) { 781*12b65585SGordon Ross /* tell the client the selected mech. */ 782*12b65585SGordon Ross oid = ctx->ctx_mech_oid; 783*12b65585SGordon Ross } else { 784*12b65585SGordon Ross /* Ommit the "supported mech." field. */ 785*12b65585SGordon Ross oid = spnego_mech_oid_NotUsed; 786*12b65585SGordon Ross } 787*12b65585SGordon Ross 788*12b65585SGordon Ross /* 789*12b65585SGordon Ross * Determine the spnego "negresult" from the 790*12b65585SGordon Ross * reply message type (from the work func). 791*12b65585SGordon Ross */ 792*12b65585SGordon Ross switch (ctx->ctx_orawtype) { 793*12b65585SGordon Ross case LSA_MTYPE_ERROR: 794*12b65585SGordon Ross ctx->ctx_negresult = spnego_negresult_rejected; 795*12b65585SGordon Ross break; 796*12b65585SGordon Ross case LSA_MTYPE_ES_DONE: 797*12b65585SGordon Ross ctx->ctx_negresult = spnego_negresult_success; 798*12b65585SGordon Ross break; 799*12b65585SGordon Ross case LSA_MTYPE_ES_CONT: 800*12b65585SGordon Ross ctx->ctx_negresult = spnego_negresult_incomplete; 801*12b65585SGordon Ross break; 802*12b65585SGordon Ross default: 803*12b65585SGordon Ross return (-1); 804*12b65585SGordon Ross } 805*12b65585SGordon Ross 806*12b65585SGordon Ross rc = spnegoCreateNegTokenTarg( 807*12b65585SGordon Ross oid, 808*12b65585SGordon Ross ctx->ctx_negresult, 809*12b65585SGordon Ross ctx->ctx_obodybuf, /* may be NULL */ 810*12b65585SGordon Ross ctx->ctx_obodylen, 811*12b65585SGordon Ross NULL, 0, 812*12b65585SGordon Ross &ctx->ctx_otoken); 813*12b65585SGordon Ross 814*12b65585SGordon Ross /* 815*12b65585SGordon Ross * Convert the SPNEGO token into binary form, 816*12b65585SGordon Ross * writing it to the output buffer. 817*12b65585SGordon Ross */ 818*12b65585SGordon Ross toklen = smbd_authsvc_bufsize; 819*12b65585SGordon Ross rc = spnegoTokenGetBinary(ctx->ctx_otoken, 820*12b65585SGordon Ross (uchar_t *)ctx->ctx_orawbuf, &toklen); 821*12b65585SGordon Ross if (rc) 822*12b65585SGordon Ross rc = NT_STATUS_INTERNAL_ERROR; 823*12b65585SGordon Ross ctx->ctx_orawlen = (uint_t)toklen; 824*12b65585SGordon Ross 825*12b65585SGordon Ross return (rc); 826*12b65585SGordon Ross } 827*12b65585SGordon Ross 828*12b65585SGordon Ross /* 829*12b65585SGordon Ross * Wrapper for "Raw NTLMSSP", which is exactly like the 830*12b65585SGordon Ross * normal (SPNEGO-wrapped) NTLMSSP but without SPNEGO. 831*12b65585SGordon Ross * Setup back-end handler for: special_mech_raw_NTLMSSP 832*12b65585SGordon Ross * Compare with smbd_authsvc_esfirst(). 833*12b65585SGordon Ross */ 834*12b65585SGordon Ross static int 835*12b65585SGordon Ross smbd_raw_ntlmssp_esfirst(authsvc_context_t *ctx) 836*12b65585SGordon Ross { 837*12b65585SGordon Ross const spnego_mech_handler_t *mh; 838*12b65585SGordon Ross int rc; 839*12b65585SGordon Ross 840*12b65585SGordon Ross mh = &smbd_auth_mech_raw_ntlmssp; 841*12b65585SGordon Ross rc = mh->mh_init(ctx); 842*12b65585SGordon Ross if (rc != 0) 843*12b65585SGordon Ross return (rc); 844*12b65585SGordon Ross 845*12b65585SGordon Ross ctx->ctx_mech_oid = mh->mh_oid; 846*12b65585SGordon Ross ctx->ctx_mh_work = mh->mh_work; 847*12b65585SGordon Ross ctx->ctx_mh_fini = mh->mh_fini; 848*12b65585SGordon Ross 849*12b65585SGordon Ross rc = smbd_raw_ntlmssp_esnext(ctx); 850*12b65585SGordon Ross 851*12b65585SGordon Ross return (rc); 852*12b65585SGordon Ross } 853*12b65585SGordon Ross 854*12b65585SGordon Ross 855*12b65585SGordon Ross /* 856*12b65585SGordon Ross * Wrapper for "Raw NTLMSSP", which is exactly like the 857*12b65585SGordon Ross * normal (SPNEGO-wrapped) NTLMSSP but without SPNEGO. 858*12b65585SGordon Ross * Just copy "raw" to "body", and vice versa. 859*12b65585SGordon Ross * Compare with smbd_authsvc_esnext, smbd_authsvc_escmn 860*12b65585SGordon Ross */ 861*12b65585SGordon Ross static int 862*12b65585SGordon Ross smbd_raw_ntlmssp_esnext(authsvc_context_t *ctx) 863*12b65585SGordon Ross { 864*12b65585SGordon Ross int rc; 865*12b65585SGordon Ross 866*12b65585SGordon Ross ctx->ctx_ibodylen = ctx->ctx_irawlen; 867*12b65585SGordon Ross (void) memcpy(ctx->ctx_ibodybuf, 868*12b65585SGordon Ross ctx->ctx_irawbuf, ctx->ctx_irawlen); 869*12b65585SGordon Ross 870*12b65585SGordon Ross rc = ctx->ctx_mh_work(ctx); 871*12b65585SGordon Ross 872*12b65585SGordon Ross ctx->ctx_orawlen = ctx->ctx_obodylen; 873*12b65585SGordon Ross (void) memcpy(ctx->ctx_orawbuf, 874*12b65585SGordon Ross ctx->ctx_obodybuf, ctx->ctx_obodylen); 875*12b65585SGordon Ross 876*12b65585SGordon Ross return (rc); 877*12b65585SGordon Ross } 878*12b65585SGordon Ross 879*12b65585SGordon Ross 880*12b65585SGordon Ross /* 881*12b65585SGordon Ross * After a successful authentication, request the access token. 882*12b65585SGordon Ross */ 883*12b65585SGordon Ross static int 884*12b65585SGordon Ross smbd_authsvc_gettoken(authsvc_context_t *ctx) 885*12b65585SGordon Ross { 886*12b65585SGordon Ross XDR xdrs; 887*12b65585SGordon Ross smb_token_t *token = NULL; 888*12b65585SGordon Ross int rc = 0; 889*12b65585SGordon Ross int len; 890*12b65585SGordon Ross 891*12b65585SGordon Ross if ((token = ctx->ctx_token) == NULL) 892*12b65585SGordon Ross return (NT_STATUS_ACCESS_DENIED); 893*12b65585SGordon Ross 894*12b65585SGordon Ross /* 895*12b65585SGordon Ross * Encode the token response 896*12b65585SGordon Ross */ 897*12b65585SGordon Ross len = xdr_sizeof(smb_token_xdr, token); 898*12b65585SGordon Ross if (len > ctx->ctx_orawlen) { 899*12b65585SGordon Ross if ((ctx->ctx_orawbuf = realloc(ctx->ctx_orawbuf, len)) == 900*12b65585SGordon Ross NULL) { 901*12b65585SGordon Ross return (NT_STATUS_INTERNAL_ERROR); 902*12b65585SGordon Ross } 903*12b65585SGordon Ross } 904*12b65585SGordon Ross 905*12b65585SGordon Ross ctx->ctx_orawtype = LSA_MTYPE_TOKEN; 906*12b65585SGordon Ross ctx->ctx_orawlen = len; 907*12b65585SGordon Ross xdrmem_create(&xdrs, ctx->ctx_orawbuf, len, XDR_ENCODE); 908*12b65585SGordon Ross if (!smb_token_xdr(&xdrs, token)) 909*12b65585SGordon Ross rc = NT_STATUS_INTERNAL_ERROR; 910*12b65585SGordon Ross xdr_destroy(&xdrs); 911*12b65585SGordon Ross 912*12b65585SGordon Ross return (rc); 913*12b65585SGordon Ross } 914*12b65585SGordon Ross 915*12b65585SGordon Ross /* 916*12b65585SGordon Ross * Initialization time code to figure out what mechanisms we support. 917*12b65585SGordon Ross * Careful with this table; the code below knows its format and may 918*12b65585SGordon Ross * skip the fist two entries to ommit Kerberos. 919*12b65585SGordon Ross */ 920*12b65585SGordon Ross static SPNEGO_MECH_OID MechTypeList[] = { 921*12b65585SGordon Ross spnego_mech_oid_Kerberos_V5, 922*12b65585SGordon Ross spnego_mech_oid_Kerberos_V5_Legacy, 923*12b65585SGordon Ross #define MECH_OID_IDX_NTLMSSP 2 924*12b65585SGordon Ross spnego_mech_oid_NTLMSSP, 925*12b65585SGordon Ross }; 926*12b65585SGordon Ross static int MechTypeCnt = sizeof (MechTypeList) / 927*12b65585SGordon Ross sizeof (MechTypeList[0]); 928*12b65585SGordon Ross 929*12b65585SGordon Ross /* This string is just like Windows. */ 930*12b65585SGordon Ross static char IgnoreSPN[] = "not_defined_in_RFC4178@please_ignore"; 931*12b65585SGordon Ross 932*12b65585SGordon Ross /* 933*12b65585SGordon Ross * Build the SPNEGO "hint" token based on the 934*12b65585SGordon Ross * configured authentication mechanisms. 935*12b65585SGordon Ross * (NTLMSSP, and maybe Kerberos) 936*12b65585SGordon Ross */ 937*12b65585SGordon Ross void 938*12b65585SGordon Ross smbd_get_authconf(smb_kmod_cfg_t *kcfg) 939*12b65585SGordon Ross { 940*12b65585SGordon Ross SPNEGO_MECH_OID *mechList = MechTypeList; 941*12b65585SGordon Ross int mechCnt = MechTypeCnt; 942*12b65585SGordon Ross SPNEGO_TOKEN_HANDLE hSpnegoToken = NULL; 943*12b65585SGordon Ross uchar_t *pBuf = kcfg->skc_negtok; 944*12b65585SGordon Ross uint32_t *pBufLen = &kcfg->skc_negtok_len; 945*12b65585SGordon Ross ulong_t tLen = sizeof (kcfg->skc_negtok); 946*12b65585SGordon Ross int rc; 947*12b65585SGordon Ross 948*12b65585SGordon Ross /* 949*12b65585SGordon Ross * In workgroup mode, skip Kerberos. 950*12b65585SGordon Ross */ 951*12b65585SGordon Ross if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) { 952*12b65585SGordon Ross mechList += MECH_OID_IDX_NTLMSSP; 953*12b65585SGordon Ross mechCnt -= MECH_OID_IDX_NTLMSSP; 954*12b65585SGordon Ross } 955*12b65585SGordon Ross 956*12b65585SGordon Ross rc = spnegoCreateNegTokenHint(mechList, mechCnt, 957*12b65585SGordon Ross (uchar_t *)IgnoreSPN, &hSpnegoToken); 958*12b65585SGordon Ross if (rc != SPNEGO_E_SUCCESS) { 959*12b65585SGordon Ross syslog(LOG_DEBUG, "smb_config_get_negtok: " 960*12b65585SGordon Ross "spnegoCreateNegTokenHint, rc=%d", rc); 961*12b65585SGordon Ross *pBufLen = 0; 962*12b65585SGordon Ross return; 963*12b65585SGordon Ross } 964*12b65585SGordon Ross rc = spnegoTokenGetBinary(hSpnegoToken, pBuf, &tLen); 965*12b65585SGordon Ross if (rc != SPNEGO_E_SUCCESS) { 966*12b65585SGordon Ross syslog(LOG_DEBUG, "smb_config_get_negtok: " 967*12b65585SGordon Ross "spnegoTokenGetBinary, rc=%d", rc); 968*12b65585SGordon Ross *pBufLen = 0; 969*12b65585SGordon Ross } else { 970*12b65585SGordon Ross *pBufLen = (uint32_t)tLen; 971*12b65585SGordon Ross } 972*12b65585SGordon Ross spnegoFreeData(hSpnegoToken); 973*12b65585SGordon Ross } 974