1*4bff34e3Sthurlow /* 2*4bff34e3Sthurlow * CDDL HEADER START 3*4bff34e3Sthurlow * 4*4bff34e3Sthurlow * The contents of this file are subject to the terms of the 5*4bff34e3Sthurlow * Common Development and Distribution License (the "License"). 6*4bff34e3Sthurlow * You may not use this file except in compliance with the License. 7*4bff34e3Sthurlow * 8*4bff34e3Sthurlow * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*4bff34e3Sthurlow * or http://www.opensolaris.org/os/licensing. 10*4bff34e3Sthurlow * See the License for the specific language governing permissions 11*4bff34e3Sthurlow * and limitations under the License. 12*4bff34e3Sthurlow * 13*4bff34e3Sthurlow * When distributing Covered Code, include this CDDL HEADER in each 14*4bff34e3Sthurlow * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*4bff34e3Sthurlow * If applicable, add the following below this CDDL HEADER, with the 16*4bff34e3Sthurlow * fields enclosed by brackets "[]" replaced with your own identifying 17*4bff34e3Sthurlow * information: Portions Copyright [yyyy] [name of copyright owner] 18*4bff34e3Sthurlow * 19*4bff34e3Sthurlow * CDDL HEADER END 20*4bff34e3Sthurlow */ 21*4bff34e3Sthurlow 22*4bff34e3Sthurlow /* 23*4bff34e3Sthurlow * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*4bff34e3Sthurlow * Use is subject to license terms. 25*4bff34e3Sthurlow */ 26*4bff34e3Sthurlow 27*4bff34e3Sthurlow #pragma ident "%Z%%M% %I% %E% SMI" 28*4bff34e3Sthurlow 29*4bff34e3Sthurlow /* 30*4bff34e3Sthurlow * Password Keychain storage mechanism. 31*4bff34e3Sthurlow */ 32*4bff34e3Sthurlow 33*4bff34e3Sthurlow #include <sys/types.h> 34*4bff34e3Sthurlow #include <sys/param.h> 35*4bff34e3Sthurlow #include <sys/errno.h> 36*4bff34e3Sthurlow #include <sys/sysmacros.h> 37*4bff34e3Sthurlow #include <sys/uio.h> 38*4bff34e3Sthurlow #include <sys/buf.h> 39*4bff34e3Sthurlow #include <sys/modctl.h> 40*4bff34e3Sthurlow #include <sys/open.h> 41*4bff34e3Sthurlow #include <sys/file.h> 42*4bff34e3Sthurlow #include <sys/kmem.h> 43*4bff34e3Sthurlow #include <sys/conf.h> 44*4bff34e3Sthurlow #include <sys/cmn_err.h> 45*4bff34e3Sthurlow #include <sys/stat.h> 46*4bff34e3Sthurlow #include <sys/ddi.h> 47*4bff34e3Sthurlow #include <sys/sunddi.h> 48*4bff34e3Sthurlow #include <sys/sunldi.h> 49*4bff34e3Sthurlow #include <sys/policy.h> 50*4bff34e3Sthurlow #include <sys/zone.h> 51*4bff34e3Sthurlow #include <sys/pathname.h> 52*4bff34e3Sthurlow #include <sys/mount.h> 53*4bff34e3Sthurlow #include <sys/sdt.h> 54*4bff34e3Sthurlow #include <fs/fs_subr.h> 55*4bff34e3Sthurlow #include <sys/devops.h> 56*4bff34e3Sthurlow #include <sys/thread.h> 57*4bff34e3Sthurlow #include <sys/mkdev.h> 58*4bff34e3Sthurlow #include <sys/avl.h> 59*4bff34e3Sthurlow #include <sys/avl_impl.h> 60*4bff34e3Sthurlow 61*4bff34e3Sthurlow #include <netsmb/smb_osdep.h> 62*4bff34e3Sthurlow 63*4bff34e3Sthurlow #include <netsmb/smb.h> 64*4bff34e3Sthurlow #include <netsmb/smb_conn.h> 65*4bff34e3Sthurlow #include <netsmb/smb_subr.h> 66*4bff34e3Sthurlow #include <netsmb/smb_dev.h> 67*4bff34e3Sthurlow #include <netsmb/smb_pass.h> 68*4bff34e3Sthurlow 69*4bff34e3Sthurlow /* 70*4bff34e3Sthurlow * The smb_ptd is a cache of Uid's, User names, passwords and domain names. 71*4bff34e3Sthurlow * It will be used for storing the password information for a user and will 72*4bff34e3Sthurlow * be used to for connections without entering the pasword again if its 73*4bff34e3Sthurlow * already keyed in by the user. Its a kind of Key-Chain mechanism 74*4bff34e3Sthurlow * implemented by Apple folks. 75*4bff34e3Sthurlow */ 76*4bff34e3Sthurlow 77*4bff34e3Sthurlow /* 78*4bff34e3Sthurlow * Information stored in the nodes: 79*4bff34e3Sthurlow * UID: Uid of the person who initiated the login request. 80*4bff34e3Sthurlow * ZoneID: ZoneID of the zone from where the login request is initiated. 81*4bff34e3Sthurlow * Username: Username in the CIFS server. 82*4bff34e3Sthurlow * Srvdom: Domain name/ Server name of the CIFS server. 83*4bff34e3Sthurlow * Password: Password of the user. 84*4bff34e3Sthurlow * For more information, see smb_pass.h and sys/avl.h 85*4bff34e3Sthurlow */ 86*4bff34e3Sthurlow 87*4bff34e3Sthurlow /* 88*4bff34e3Sthurlow * Information retrieved from the node. 89*4bff34e3Sthurlow * Node/password information can only be retrived with a call 90*4bff34e3Sthurlow * to smb_pkey_getpw(). Password never gets copied to the userspace. 91*4bff34e3Sthurlow * It will be copied to the Kernel data structure smbioc_ossn->ioc_password 92*4bff34e3Sthurlow * when needed for doing the "Session Setup". All other calls will return 93*4bff34e3Sthurlow * either a success or a failure. 94*4bff34e3Sthurlow */ 95*4bff34e3Sthurlow 96*4bff34e3Sthurlow avl_tree_t smb_ptd; /* AVL password tree descriptor */ 97*4bff34e3Sthurlow unsigned int smb_list_len = 0; /* No. of elements in the tree. */ 98*4bff34e3Sthurlow kmutex_t smb_ptd_lock; /* Mutex lock for controlled access */ 99*4bff34e3Sthurlow 100*4bff34e3Sthurlow /* 101*4bff34e3Sthurlow * This routine is called by AVL tree calls when they want to find a 102*4bff34e3Sthurlow * node, find the next position in the tree to add or for deletion. 103*4bff34e3Sthurlow * Compare nodes from the tree to find the actual node based on 104*4bff34e3Sthurlow * uid/zoneid/username/domainname. 105*4bff34e3Sthurlow */ 106*4bff34e3Sthurlow int 107*4bff34e3Sthurlow smb_pkey_cmp(const void *a, const void *b) 108*4bff34e3Sthurlow { 109*4bff34e3Sthurlow const smb_passid_t *pa = (smb_passid_t *)a; 110*4bff34e3Sthurlow const smb_passid_t *pb = (smb_passid_t *)b; 111*4bff34e3Sthurlow int duser, dsrv; 112*4bff34e3Sthurlow 113*4bff34e3Sthurlow ASSERT(MUTEX_HELD(&smb_ptd_lock)); 114*4bff34e3Sthurlow 115*4bff34e3Sthurlow /* 116*4bff34e3Sthurlow * The nodes are added sorted on the uid/zoneid/domainname/username 117*4bff34e3Sthurlow * We will do this: 118*4bff34e3Sthurlow * Compare uid's. The owner who stored the node gets access. 119*4bff34e3Sthurlow * Then zoneid to check if the access is from the same zone. 120*4bff34e3Sthurlow * Compare usernames. 121*4bff34e3Sthurlow * If the above are same, then compare domain/server names. 122*4bff34e3Sthurlow */ 123*4bff34e3Sthurlow if (pa->uid < pb->uid) 124*4bff34e3Sthurlow return (-1); 125*4bff34e3Sthurlow if (pa->uid > pb->uid) 126*4bff34e3Sthurlow return (+1); 127*4bff34e3Sthurlow if (pa->zoneid < pb->zoneid) 128*4bff34e3Sthurlow return (-1); 129*4bff34e3Sthurlow if (pa->zoneid > pb->zoneid) 130*4bff34e3Sthurlow return (+1); 131*4bff34e3Sthurlow dsrv = strcasecmp(pa->srvdom, pb->srvdom); 132*4bff34e3Sthurlow if (dsrv < 0) 133*4bff34e3Sthurlow return (-1); 134*4bff34e3Sthurlow if (dsrv > 0) 135*4bff34e3Sthurlow return (+1); 136*4bff34e3Sthurlow duser = strcasecmp(pa->username, pb->username); 137*4bff34e3Sthurlow if (duser < 0) 138*4bff34e3Sthurlow return (-1); 139*4bff34e3Sthurlow if (duser > 0) 140*4bff34e3Sthurlow return (+1); 141*4bff34e3Sthurlow return (0); 142*4bff34e3Sthurlow } 143*4bff34e3Sthurlow 144*4bff34e3Sthurlow /* 145*4bff34e3Sthurlow * Initialization of the code that deals with uid and passwords. 146*4bff34e3Sthurlow */ 147*4bff34e3Sthurlow void 148*4bff34e3Sthurlow smb_pkey_init() 149*4bff34e3Sthurlow { 150*4bff34e3Sthurlow avl_create(&smb_ptd, 151*4bff34e3Sthurlow smb_pkey_cmp, 152*4bff34e3Sthurlow sizeof (smb_passid_t), 153*4bff34e3Sthurlow offsetof(smb_passid_t, 154*4bff34e3Sthurlow cpnode)); 155*4bff34e3Sthurlow mutex_init(&smb_ptd_lock, NULL, MUTEX_DEFAULT, NULL); 156*4bff34e3Sthurlow } 157*4bff34e3Sthurlow 158*4bff34e3Sthurlow /* 159*4bff34e3Sthurlow * Destroy the full AVL tree. 160*4bff34e3Sthurlow */ 161*4bff34e3Sthurlow void 162*4bff34e3Sthurlow smb_pkey_fini() 163*4bff34e3Sthurlow { 164*4bff34e3Sthurlow smb_pkey_deluid((uid_t)-1, CRED()); 165*4bff34e3Sthurlow avl_destroy(&smb_ptd); 166*4bff34e3Sthurlow mutex_destroy(&smb_ptd_lock); 167*4bff34e3Sthurlow } 168*4bff34e3Sthurlow 169*4bff34e3Sthurlow /* 170*4bff34e3Sthurlow * Driver unload calls this to ask if we 171*4bff34e3Sthurlow * have any stored passwords 172*4bff34e3Sthurlow */ 173*4bff34e3Sthurlow int 174*4bff34e3Sthurlow smb_pkey_idle() 175*4bff34e3Sthurlow { 176*4bff34e3Sthurlow int n; 177*4bff34e3Sthurlow 178*4bff34e3Sthurlow mutex_enter(&smb_ptd_lock); 179*4bff34e3Sthurlow n = avl_numnodes(&smb_ptd); 180*4bff34e3Sthurlow mutex_exit(&smb_ptd_lock); 181*4bff34e3Sthurlow 182*4bff34e3Sthurlow return ((n) ? EBUSY : 0); 183*4bff34e3Sthurlow } 184*4bff34e3Sthurlow 185*4bff34e3Sthurlow int 186*4bff34e3Sthurlow smb_node_delete(smb_passid_t *tmp) 187*4bff34e3Sthurlow { 188*4bff34e3Sthurlow ASSERT(MUTEX_HELD(&smb_ptd_lock)); 189*4bff34e3Sthurlow avl_remove(&smb_ptd, tmp); 190*4bff34e3Sthurlow smb_strfree(tmp->srvdom); 191*4bff34e3Sthurlow smb_strfree(tmp->username); 192*4bff34e3Sthurlow kmem_free(tmp, sizeof (*tmp)); 193*4bff34e3Sthurlow return (0); 194*4bff34e3Sthurlow } 195*4bff34e3Sthurlow 196*4bff34e3Sthurlow 197*4bff34e3Sthurlow /* 198*4bff34e3Sthurlow * Remove a node from the AVL tree identified by cpid. 199*4bff34e3Sthurlow */ 200*4bff34e3Sthurlow int 201*4bff34e3Sthurlow smb_pkey_del(smbioc_pk_t *pk, cred_t *cr) 202*4bff34e3Sthurlow { 203*4bff34e3Sthurlow avl_index_t where; 204*4bff34e3Sthurlow smb_passid_t buf, *cpid, *tmp; 205*4bff34e3Sthurlow uid_t uid; 206*4bff34e3Sthurlow 207*4bff34e3Sthurlow tmp = &buf; 208*4bff34e3Sthurlow uid = pk->pk_uid; 209*4bff34e3Sthurlow if (uid == (uid_t)-1) 210*4bff34e3Sthurlow uid = crgetruid(cr); 211*4bff34e3Sthurlow else { 212*4bff34e3Sthurlow if (secpolicy_smbfs_login(cr, uid)) 213*4bff34e3Sthurlow return (EPERM); 214*4bff34e3Sthurlow } 215*4bff34e3Sthurlow tmp->uid = uid; 216*4bff34e3Sthurlow tmp->zoneid = getzoneid(); 217*4bff34e3Sthurlow tmp->srvdom = pk->pk_dom; 218*4bff34e3Sthurlow tmp->username = pk->pk_usr; 219*4bff34e3Sthurlow 220*4bff34e3Sthurlow mutex_enter(&smb_ptd_lock); 221*4bff34e3Sthurlow if ((cpid = (smb_passid_t *)avl_find(&smb_ptd, 222*4bff34e3Sthurlow tmp, &where)) != NULL) { 223*4bff34e3Sthurlow smb_node_delete(cpid); 224*4bff34e3Sthurlow } 225*4bff34e3Sthurlow mutex_exit(&smb_ptd_lock); 226*4bff34e3Sthurlow 227*4bff34e3Sthurlow return (0); 228*4bff34e3Sthurlow } 229*4bff34e3Sthurlow 230*4bff34e3Sthurlow /* 231*4bff34e3Sthurlow * Delete the entries owned by a particular user 232*4bff34e3Sthurlow * based on uid. We go through all the nodes and 233*4bff34e3Sthurlow * delete the nodes whereever the uid matches. 234*4bff34e3Sthurlow * 235*4bff34e3Sthurlow * Also implements "delete all" when uid == -1. 236*4bff34e3Sthurlow * 237*4bff34e3Sthurlow * You must have privilege to use any uid other 238*4bff34e3Sthurlow * than your real uid. 239*4bff34e3Sthurlow */ 240*4bff34e3Sthurlow int 241*4bff34e3Sthurlow smb_pkey_deluid(uid_t ioc_uid, cred_t *cr) 242*4bff34e3Sthurlow { 243*4bff34e3Sthurlow smb_passid_t *cpid, *tmp; 244*4bff34e3Sthurlow 245*4bff34e3Sthurlow if (secpolicy_smbfs_login(cr, ioc_uid)) 246*4bff34e3Sthurlow return (EPERM); 247*4bff34e3Sthurlow 248*4bff34e3Sthurlow mutex_enter(&smb_ptd_lock); 249*4bff34e3Sthurlow for (tmp = avl_first(&smb_ptd); tmp != NULL; 250*4bff34e3Sthurlow tmp = cpid) { 251*4bff34e3Sthurlow cpid = AVL_NEXT(&smb_ptd, tmp); 252*4bff34e3Sthurlow if (ioc_uid == (uid_t)-1 || 253*4bff34e3Sthurlow ioc_uid == tmp->uid) { 254*4bff34e3Sthurlow /* 255*4bff34e3Sthurlow * Delete the node. 256*4bff34e3Sthurlow */ 257*4bff34e3Sthurlow smb_node_delete(tmp); 258*4bff34e3Sthurlow } 259*4bff34e3Sthurlow } 260*4bff34e3Sthurlow mutex_exit(&smb_ptd_lock); 261*4bff34e3Sthurlow 262*4bff34e3Sthurlow return (0); 263*4bff34e3Sthurlow } 264*4bff34e3Sthurlow 265*4bff34e3Sthurlow /* 266*4bff34e3Sthurlow * Add entry or modify existing. 267*4bff34e3Sthurlow * Check for existing entry.. 268*4bff34e3Sthurlow * If present, delete. 269*4bff34e3Sthurlow * Now, add the new entry. 270*4bff34e3Sthurlow */ 271*4bff34e3Sthurlow int 272*4bff34e3Sthurlow smb_pkey_add(smbioc_pk_t *pk, cred_t *cr) 273*4bff34e3Sthurlow { 274*4bff34e3Sthurlow avl_tree_t *t = &smb_ptd; 275*4bff34e3Sthurlow avl_index_t where; 276*4bff34e3Sthurlow smb_passid_t *tmp, *cpid; 277*4bff34e3Sthurlow int ret; 278*4bff34e3Sthurlow uid_t uid; 279*4bff34e3Sthurlow 280*4bff34e3Sthurlow uid = pk->pk_uid; 281*4bff34e3Sthurlow if (uid == (uid_t)-1) 282*4bff34e3Sthurlow uid = crgetruid(cr); 283*4bff34e3Sthurlow else { 284*4bff34e3Sthurlow if (secpolicy_smbfs_login(cr, uid)) 285*4bff34e3Sthurlow return (EPERM); 286*4bff34e3Sthurlow } 287*4bff34e3Sthurlow cpid = kmem_zalloc(sizeof (smb_passid_t), KM_SLEEP); 288*4bff34e3Sthurlow cpid->uid = uid; 289*4bff34e3Sthurlow cpid->zoneid = getzoneid(); 290*4bff34e3Sthurlow cpid->srvdom = smb_strdup(pk->pk_dom); 291*4bff34e3Sthurlow cpid->username = smb_strdup(pk->pk_usr); 292*4bff34e3Sthurlow smb_oldlm_hash(pk->pk_pass, cpid->lmhash); 293*4bff34e3Sthurlow smb_ntlmv1hash(pk->pk_pass, cpid->nthash); 294*4bff34e3Sthurlow 295*4bff34e3Sthurlow /* 296*4bff34e3Sthurlow * XXX: Instead of calling smb_pkey_check here, 297*4bff34e3Sthurlow * should call avl_find directly, and hold the 298*4bff34e3Sthurlow * lock across: avl_find, avl_remove, avl_insert. 299*4bff34e3Sthurlow */ 300*4bff34e3Sthurlow 301*4bff34e3Sthurlow /* If it already exists, delete it. */ 302*4bff34e3Sthurlow ret = smb_pkey_check(pk, cr); 303*4bff34e3Sthurlow if (ret == 0) { 304*4bff34e3Sthurlow smb_pkey_del(pk, cr); 305*4bff34e3Sthurlow } 306*4bff34e3Sthurlow 307*4bff34e3Sthurlow mutex_enter(&smb_ptd_lock); 308*4bff34e3Sthurlow tmp = (smb_passid_t *)avl_find(t, cpid, &where); 309*4bff34e3Sthurlow if (tmp == NULL) { 310*4bff34e3Sthurlow avl_insert(t, cpid, where); 311*4bff34e3Sthurlow } else { 312*4bff34e3Sthurlow smb_strfree(cpid->srvdom); 313*4bff34e3Sthurlow smb_strfree(cpid->username); 314*4bff34e3Sthurlow kmem_free(cpid, sizeof (smb_passid_t)); 315*4bff34e3Sthurlow } 316*4bff34e3Sthurlow mutex_exit(&smb_ptd_lock); 317*4bff34e3Sthurlow 318*4bff34e3Sthurlow return (0); 319*4bff34e3Sthurlow } 320*4bff34e3Sthurlow 321*4bff34e3Sthurlow /* 322*4bff34e3Sthurlow * Determine if a node with uid,zoneid, uname & dname exists in the tree 323*4bff34e3Sthurlow * given the information. Does NOT return the stored password. 324*4bff34e3Sthurlow */ 325*4bff34e3Sthurlow int 326*4bff34e3Sthurlow smb_pkey_check(smbioc_pk_t *pk, cred_t *cr) 327*4bff34e3Sthurlow { 328*4bff34e3Sthurlow avl_tree_t *t = &smb_ptd; 329*4bff34e3Sthurlow avl_index_t where; 330*4bff34e3Sthurlow smb_passid_t *tmp, *cpid; 331*4bff34e3Sthurlow int error = ENOENT; 332*4bff34e3Sthurlow uid_t uid; 333*4bff34e3Sthurlow 334*4bff34e3Sthurlow uid = pk->pk_uid; 335*4bff34e3Sthurlow if (uid == (uid_t)-1) 336*4bff34e3Sthurlow uid = crgetruid(cr); 337*4bff34e3Sthurlow else { 338*4bff34e3Sthurlow if (secpolicy_smbfs_login(cr, uid)) 339*4bff34e3Sthurlow return (EPERM); 340*4bff34e3Sthurlow } 341*4bff34e3Sthurlow cpid = kmem_alloc(sizeof (smb_passid_t), KM_SLEEP); 342*4bff34e3Sthurlow cpid->uid = uid; 343*4bff34e3Sthurlow cpid->zoneid = getzoneid(); 344*4bff34e3Sthurlow cpid->srvdom = pk->pk_dom; 345*4bff34e3Sthurlow cpid->username = pk->pk_usr; 346*4bff34e3Sthurlow 347*4bff34e3Sthurlow mutex_enter(&smb_ptd_lock); 348*4bff34e3Sthurlow tmp = (smb_passid_t *)avl_find(t, cpid, &where); 349*4bff34e3Sthurlow if (tmp != NULL) 350*4bff34e3Sthurlow error = 0; 351*4bff34e3Sthurlow mutex_exit(&smb_ptd_lock); 352*4bff34e3Sthurlow 353*4bff34e3Sthurlow kmem_free(cpid, sizeof (smb_passid_t)); 354*4bff34e3Sthurlow return (error); 355*4bff34e3Sthurlow } 356*4bff34e3Sthurlow 357*4bff34e3Sthurlow /* 358*4bff34e3Sthurlow * Interface function between the keychain mechanism and SMB password 359*4bff34e3Sthurlow * handling during Session Setup. Internal form of smb_pkey_check(). 360*4bff34e3Sthurlow * Copies the password hashes into the VC. 361*4bff34e3Sthurlow */ 362*4bff34e3Sthurlow int 363*4bff34e3Sthurlow smb_pkey_getpwh(struct smb_vc *vcp, cred_t *cr) 364*4bff34e3Sthurlow { 365*4bff34e3Sthurlow avl_tree_t *t = &smb_ptd; 366*4bff34e3Sthurlow avl_index_t where; 367*4bff34e3Sthurlow smb_passid_t *tmp, *cpid; 368*4bff34e3Sthurlow int error = ENOENT; 369*4bff34e3Sthurlow 370*4bff34e3Sthurlow cpid = kmem_alloc(sizeof (smb_passid_t), KM_SLEEP); 371*4bff34e3Sthurlow cpid->uid = crgetruid(cr); 372*4bff34e3Sthurlow cpid->zoneid = getzoneid(); 373*4bff34e3Sthurlow cpid->username = vcp->vc_username; 374*4bff34e3Sthurlow 375*4bff34e3Sthurlow if (vcp->vc_vopt & SMBVOPT_KC_DOMAIN) 376*4bff34e3Sthurlow cpid->srvdom = vcp->vc_domain; 377*4bff34e3Sthurlow else 378*4bff34e3Sthurlow cpid->srvdom = vcp->vc_srvname; 379*4bff34e3Sthurlow 380*4bff34e3Sthurlow mutex_enter(&smb_ptd_lock); 381*4bff34e3Sthurlow tmp = (smb_passid_t *)avl_find(t, cpid, &where); 382*4bff34e3Sthurlow if (tmp != NULL) { 383*4bff34e3Sthurlow bcopy(tmp->lmhash, vcp->vc_lmhash, SMB_PWH_MAX); 384*4bff34e3Sthurlow bcopy(tmp->nthash, vcp->vc_nthash, SMB_PWH_MAX); 385*4bff34e3Sthurlow error = 0; 386*4bff34e3Sthurlow } 387*4bff34e3Sthurlow mutex_exit(&smb_ptd_lock); 388*4bff34e3Sthurlow 389*4bff34e3Sthurlow kmem_free(cpid, sizeof (smb_passid_t)); 390*4bff34e3Sthurlow return (error); 391*4bff34e3Sthurlow } 392