Print this page
    
NEX-18907 File Access Auditing does not work with SMB Kerberos authentication
Review by: Gordon Ross <gordon.ross@nexenta.com>
Review by: Evan Layton <evan.layton@nexenta.com>
NEX-13644 File access audit logging
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-15558 SMB logon fails during 1st second after service start
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15558 SMB logon fails during 1st second after service start
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-8707 smb/server in 4.0.x does not accept username@hostname
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-4083 Upstream changes from illumos 5917 and 5995
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
SMB-149 mount.cifs RedHat\Centos 6 doesn't work with default security options
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/smbsrv/smbd/smbd_logon.c
          +++ new/usr/src/cmd/smbsrv/smbd/smbd_logon.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  
    | 
      ↓ open down ↓ | 
    12 lines elided | 
    
      ↑ open up ↑ | 
  
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23      - * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
       23 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  24   24   */
  25   25  
  26   26  #include <sys/types.h>
  27   27  #include <errno.h>
  28   28  #include <synch.h>
  29   29  #include <stdio.h>
  30   30  #include <stdlib.h>
  31   31  #include <unistd.h>
  32   32  #include <string.h>
  33   33  #include <strings.h>
  34   34  #include <syslog.h>
  35   35  #include <fcntl.h>
  36   36  #include <bsm/adt.h>
  37   37  #include <bsm/adt_event.h>
  38   38  #include <bsm/audit_uevents.h>
  39   39  #include <pwd.h>
  40   40  #include <nss_dbdefs.h>
  41   41  #include <sys/idmap.h>
  42   42  #include "smbd.h"
  43   43  
  44   44  
  45   45  /*
  46   46   * An audit session is established at user logon and terminated at user
  47   47   * logoff.
  48   48   *
  49   49   * SMB audit handles are allocated when users logon (SmbSessionSetupX)
  50   50   * and deallocted when a user logs off (SmbLogoffX).  Each time an SMB
  51   51   * audit handle is allocated it is added to a global list.
  52   52   */
  53   53  typedef struct smb_audit {
  54   54          struct smb_audit *sa_next;
  55   55          adt_session_data_t *sa_handle;
  56   56          uid_t sa_uid;
  57   57          gid_t sa_gid;
  58   58          uint32_t sa_audit_sid;
  59   59          uint32_t sa_refcnt;
  60   60          char *sa_domain;
  61   61          char *sa_username;
  62   62  } smb_audit_t;
  63   63  
  64   64  static smb_audit_t *smbd_audit_list;
  65   65  static mutex_t smbd_audit_lock;
  66   66  
  67   67  /*
  68   68   * Unique identifier for audit sessions in the audit list.
  
    | 
      ↓ open down ↓ | 
    35 lines elided | 
    
      ↑ open up ↑ | 
  
  69   69   * Used to lookup an audit session on logoff.
  70   70   */
  71   71  static uint32_t smbd_audit_sid;
  72   72  
  73   73  static void smbd_audit_link(smb_audit_t *);
  74   74  static smb_audit_t *smbd_audit_unlink(uint32_t);
  75   75  
  76   76  
  77   77  /*
  78   78   * Invoked at user logon due to SmbSessionSetupX.  Authenticate the
  79      - * user, start an audit session and audit the event.
       79 + * user.
       80 + *
       81 + * On error, returns NULL, and status in user_info->lg_status
  80   82   */
  81   83  smb_token_t *
  82   84  smbd_user_auth_logon(smb_logon_t *user_info)
  83   85  {
  84   86          smb_token_t *token;
  85      -        smb_audit_t *entry;
  86      -        adt_session_data_t *ah;
  87      -        adt_event_data_t *event;
  88   87          smb_logon_t tmp_user;
  89      -        au_tid_addr_t termid;
  90      -        char sidbuf[SMB_SID_STRSZ];
  91      -        char *username;
  92      -        char *domain;
  93      -        uid_t uid;
  94      -        gid_t gid;
  95      -        char *sid;
  96      -        int status;
  97      -        int retval;
       88 +        char *p;
       89 +        char *buf = NULL;
  98   90  
  99   91          if (user_info->lg_username == NULL ||
 100   92              user_info->lg_domain == NULL ||
 101   93              user_info->lg_workstation == NULL) {
       94 +                user_info->lg_status = NT_STATUS_INVALID_PARAMETER;
 102   95                  return (NULL);
 103   96          }
 104   97  
       98 +        /*
       99 +         * Avoid modifying the caller-provided struct because it
      100 +         * may or may not point to allocated strings etc.
      101 +         * Copy to tmp_user, auth, then copy the (out) lg_status
      102 +         * member back to the caller-provided struct.
      103 +         */
 105  104          tmp_user = *user_info;
 106  105          if (tmp_user.lg_username[0] == '\0') {
 107  106                  tmp_user.lg_flags |= SMB_ATF_ANON;
 108  107                  tmp_user.lg_e_username = "anonymous";
 109  108          } else {
 110  109                  tmp_user.lg_e_username = tmp_user.lg_username;
 111  110          }
 112      -        tmp_user.lg_e_domain = tmp_user.lg_domain;
 113  111  
 114      -        if ((token = smb_logon(&tmp_user)) == NULL) {
      112 +        /* Handle user@domain format. */
      113 +        if (tmp_user.lg_domain[0] == '\0' &&
      114 +            (p = strchr(tmp_user.lg_e_username, '@')) != NULL) {
      115 +                buf = strdup(tmp_user.lg_e_username);
      116 +                p = buf + (p - tmp_user.lg_e_username);
      117 +                *p = '\0';
      118 +                tmp_user.lg_e_domain = p + 1;
      119 +                tmp_user.lg_e_username = buf;
      120 +        } else {
      121 +                tmp_user.lg_e_domain = tmp_user.lg_domain;
      122 +        }
      123 +
      124 +        token = smb_logon(&tmp_user);
      125 +        user_info->lg_status = tmp_user.lg_status;
      126 +
      127 +        if (token == NULL) {
      128 +                if (user_info->lg_status == 0) /* should not happen */
      129 +                        user_info->lg_status = NT_STATUS_INTERNAL_ERROR;
      130 +        }
      131 +
      132 +        if (!smbd_logon_audit(token, &user_info->lg_clnt_ipaddr,
      133 +            tmp_user.lg_e_username, tmp_user.lg_e_domain)) {
      134 +                user_info->lg_status = NT_STATUS_AUDIT_FAILED;
      135 +                goto errout;
      136 +        }
      137 +
      138 +        if (token) {
      139 +                smb_autohome_add(token);
      140 +        }
      141 +
      142 +        if (buf != NULL)
      143 +                free(buf);
      144 +
      145 +        return (token);
      146 +
      147 +errout:
      148 +        if (buf != NULL)
      149 +                free(buf);
      150 +        smb_token_destroy(token);
      151 +        return (NULL);
      152 +}
      153 +
      154 +/* Start an audit session and audit the event. */
      155 +boolean_t
      156 +smbd_logon_audit(smb_token_t *token, smb_inaddr_t *ipaddr, char *username,
      157 +    char *domain)
      158 +{
      159 +        smb_audit_t *entry;
      160 +        adt_session_data_t *ah = NULL;
      161 +        adt_event_data_t *event;
      162 +        au_tid_addr_t termid;
      163 +        char sidbuf[SMB_SID_STRSZ];
      164 +        uid_t uid;
      165 +        gid_t gid;
      166 +        char *sid;
      167 +        int status;
      168 +        int retval;
      169 +
      170 +        if (username == NULL)
      171 +                username = "";
      172 +
      173 +        if (token == NULL) {
 115  174                  uid = ADT_NO_ATTRIB;
 116  175                  gid = ADT_NO_ATTRIB;
 117  176                  sid = NT_NULL_SIDSTR;
 118      -                username = tmp_user.lg_e_username;
 119      -                domain = tmp_user.lg_e_domain;
      177 +                /* use the 'default' username and domain we were given */
 120  178                  status = ADT_FAILURE;
 121  179                  retval = ADT_FAIL_VALUE_AUTH;
 122  180          } else {
 123  181                  uid = token->tkn_user.i_id;
 124  182                  gid = token->tkn_primary_grp.i_id;
 125  183                  smb_sid_tostr(token->tkn_user.i_sid, sidbuf);
 126  184                  sid = sidbuf;
 127  185                  username = token->tkn_account_name;
 128  186                  domain = token->tkn_domain_name;
 129  187                  status = ADT_SUCCESS;
 130  188                  retval = ADT_SUCCESS;
 131  189          }
 132  190  
 133  191          if (adt_start_session(&ah, NULL, 0)) {
 134  192                  syslog(LOG_AUTH | LOG_ALERT, "adt_start_session: %m");
 135      -                smb_token_destroy(token);
 136      -                return (NULL);
      193 +                goto errout;
 137  194          }
 138  195  
 139  196          if ((event = adt_alloc_event(ah, ADT_smbd_session)) == NULL) {
 140  197                  syslog(LOG_AUTH | LOG_ALERT,
 141  198                      "adt_alloc_event(ADT_smbd_session): %m");
 142      -                (void) adt_end_session(ah);
 143      -                smb_token_destroy(token);
 144      -                return (NULL);
      199 +                goto errout;
 145  200          }
 146  201  
 147  202          (void) memset(&termid, 0, sizeof (au_tid_addr_t));
 148      -        termid.at_port = user_info->lg_local_port;
      203 +        termid.at_port = 445;
 149  204  
 150      -        if (user_info->lg_clnt_ipaddr.a_family == AF_INET) {
 151      -                termid.at_addr[0] = user_info->lg_clnt_ipaddr.a_ipv4;
      205 +        if (ipaddr->a_family == AF_INET) {
      206 +                termid.at_addr[0] = ipaddr->a_ipv4;
 152  207                  termid.at_type = AU_IPv4;
 153  208          } else {
 154      -                bcopy(&user_info->lg_clnt_ipaddr.a_ip, termid.at_addr,
      209 +                bcopy(&ipaddr->a_ip, termid.at_addr,
 155  210                      sizeof (in6_addr_t));
 156  211                  termid.at_type = AU_IPv6;
 157  212          }
 158  213          adt_set_termid(ah, &termid);
 159  214  
 160  215          if (adt_set_user(ah, uid, gid, uid, gid, NULL, ADT_NEW)) {
 161  216                  syslog(LOG_AUTH | LOG_ALERT, "adt_set_user: %m");
 162  217                  adt_free_event(event);
 163      -                (void) adt_end_session(ah);
 164      -                smb_token_destroy(token);
 165      -                return (NULL);
      218 +                goto errout;
 166  219          }
 167  220  
 168  221          event->adt_smbd_session.domain = domain;
 169  222          event->adt_smbd_session.username = username;
 170  223          event->adt_smbd_session.sid = sid;
 171  224  
 172  225          if (adt_put_event(event, status, retval))
 173  226                  syslog(LOG_AUTH | LOG_ALERT, "adt_put_event: %m");
 174  227  
 175  228          adt_free_event(event);
 176  229  
 177  230          if (token) {
 178  231                  if ((entry = malloc(sizeof (smb_audit_t))) == NULL) {
 179  232                          syslog(LOG_ERR, "smbd_user_auth_logon: %m");
 180      -                        (void) adt_end_session(ah);
 181      -                        smb_token_destroy(token);
 182      -                        return (NULL);
      233 +                        goto errout;
 183  234                  }
 184  235  
 185  236                  entry->sa_handle = ah;
 186  237                  entry->sa_uid = uid;
 187  238                  entry->sa_gid = gid;
 188  239                  entry->sa_username = strdup(username);
 189  240                  entry->sa_domain = strdup(domain);
 190  241  
 191      -                smb_autohome_add(token);
 192  242                  smbd_audit_link(entry);
 193  243                  token->tkn_audit_sid = entry->sa_audit_sid;
      244 +                adt_get_auid(ah, &token->tkn_auid);
      245 +                adt_get_mask(ah, &token->tkn_amask);
      246 +                adt_get_asid(ah, &token->tkn_asid);
 194  247          }
 195  248  
 196      -        return (token);
      249 +        return (B_TRUE);
      250 +errout:
      251 +        if (ah != NULL)
      252 +                (void) adt_end_session(ah);
      253 +
      254 +        return (B_FALSE);
 197  255  }
 198  256  
 199  257  /*
 200  258   * Logon due to a subsequent SmbSessionSetupX on an existing session.
 201  259   * The user was authenticated during the initial session setup.
 202  260   */
 203  261  void
 204  262  smbd_user_nonauth_logon(uint32_t audit_sid)
 205  263  {
 206  264          smb_audit_t *entry;
 207  265  
 208  266          (void) mutex_lock(&smbd_audit_lock);
 209  267          entry = smbd_audit_list;
 210  268  
 211  269          while (entry) {
 212  270                  if (entry->sa_audit_sid == audit_sid) {
 213  271                          ++entry->sa_refcnt;
 214  272                          break;
 215  273                  }
 216  274  
 217  275                  entry = entry->sa_next;
 218  276          }
 219  277  
 220  278          (void) mutex_unlock(&smbd_audit_lock);
 221  279  }
 222  280  
 223  281  /*
 224  282   * Invoked at user logoff due to SmbLogoffX.  If this is the final
 225  283   * logoff for this user on the session, audit the event and terminate
 226  284   * the audit session.
 227  285   */
 228  286  void
 229  287  smbd_user_auth_logoff(uint32_t audit_sid)
 230  288  {
 231  289          smb_audit_t *entry;
 232  290          adt_session_data_t *ah;
 233  291          adt_event_data_t *event;
 234  292          struct passwd pw;
 235  293          char buf[NSS_LINELEN_PASSWD];
 236  294  
 237  295          if ((entry = smbd_audit_unlink(audit_sid)) == NULL)
 238  296                  return;
 239  297  
 240  298          if (IDMAP_ID_IS_EPHEMERAL(entry->sa_uid)) {
 241  299                  smb_autohome_remove(entry->sa_username);
 242  300          } else {
 243  301                  if (getpwuid_r(entry->sa_uid, &pw, buf, sizeof (buf)) == NULL)
 244  302                          return;
 245  303  
 246  304                  smb_autohome_remove(pw.pw_name);
 247  305          }
 248  306  
 249  307          ah = entry->sa_handle;
 250  308  
 251  309          if ((event = adt_alloc_event(ah, ADT_smbd_logoff)) == NULL) {
 252  310                  syslog(LOG_AUTH | LOG_ALERT,
 253  311                      "adt_alloc_event(ADT_smbd_logoff): %m");
 254  312          } else {
 255  313                  event->adt_smbd_logoff.domain = entry->sa_domain;
 256  314                  event->adt_smbd_logoff.username = entry->sa_username;
 257  315  
 258  316                  if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS))
 259  317                          syslog(LOG_AUTH | LOG_ALERT, "adt_put_event: %m");
 260  318  
 261  319                  adt_free_event(event);
 262  320          }
 263  321  
 264  322          (void) adt_end_session(ah);
 265  323  
 266  324          free(entry->sa_username);
 267  325          free(entry->sa_domain);
 268  326          free(entry);
 269  327  }
 270  328  
 271  329  /*
 272  330   * Allocate an id and link an audit handle onto the global list.
 273  331   */
 274  332  static void
 275  333  smbd_audit_link(smb_audit_t *entry)
 276  334  {
 277  335          (void) mutex_lock(&smbd_audit_lock);
 278  336  
 279  337          do {
 280  338                  ++smbd_audit_sid;
 281  339          } while ((smbd_audit_sid == 0) || (smbd_audit_sid == (uint32_t)-1));
 282  340  
 283  341          entry->sa_audit_sid = smbd_audit_sid;
 284  342          entry->sa_refcnt = 1;
 285  343          entry->sa_next = smbd_audit_list;
 286  344          smbd_audit_list = entry;
 287  345  
 288  346          (void) mutex_unlock(&smbd_audit_lock);
 289  347  }
 290  348  
 291  349  /*
 292  350   * Unlink an audit handle.  If the reference count reaches 0, the entry
 293  351   * is removed from the list and returned.  Otherwise the entry remains
 294  352   * on the list and a null pointer is returned.
 295  353   */
 296  354  static smb_audit_t *
 297  355  smbd_audit_unlink(uint32_t audit_sid)
 298  356  {
 299  357          smb_audit_t *entry;
 300  358          smb_audit_t **ppe;
 301  359  
 302  360          (void) mutex_lock(&smbd_audit_lock);
 303  361          ppe = &smbd_audit_list;
 304  362  
 305  363          while (*ppe) {
 306  364                  entry = *ppe;
 307  365  
 308  366                  if (entry->sa_audit_sid == audit_sid) {
 309  367                          if (entry->sa_refcnt == 0)
 310  368                                  break;
 311  369  
 312  370                          if ((--entry->sa_refcnt) != 0)
 313  371                                  break;
 314  372  
 315  373                          *ppe = entry->sa_next;
 316  374                          (void) mutex_unlock(&smbd_audit_lock);
 317  375                          return (entry);
 318  376                  }
 319  377  
 320  378                  ppe = &(*ppe)->sa_next;
 321  379          }
 322  380  
 323  381          (void) mutex_unlock(&smbd_audit_lock);
 324  382          return (NULL);
 325  383  }
  
    | 
      ↓ open down ↓ | 
    119 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX