1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* 29 * External interface to the libsmbfs/netsmb keychain 30 * storage mechanism. This interface is consumed by 31 * the "smbutil" commands: login, logout, ... 32 * and by the SMBFS PAM module. 33 */ 34 35 #include <sys/types.h> 36 37 #include <errno.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 #include <libintl.h> 43 44 #include <cflib.h> 45 #include <netsmb/smb_dev.h> 46 #include <netsmb/smb_lib.h> 47 #include <netsmb/smb_keychain.h> 48 49 #include "charsets.h" 50 #include "private.h" 51 #include "ntlm.h" 52 53 /* common func. for add/del/chk */ 54 static int 55 smbfs_keychain_cmn( 56 int cmd, 57 uid_t uid, 58 const char *dom, 59 const char *usr, 60 uchar_t *lmhash, 61 uchar_t *nthash) 62 { 63 smbioc_pk_t pk; 64 int err, fd, sz; 65 66 memset(&pk, 0, sizeof (pk)); 67 pk.pk_uid = uid; 68 err = 0; 69 fd = -1; 70 71 switch (cmd) { 72 73 case SMBIOC_PK_ADD: 74 /* 75 * Add password hashes to the keychain. 76 */ 77 if (lmhash == NULL || nthash == NULL) { 78 err = SMB_KEYCHAIN_BADPASSWD; 79 goto out; 80 } 81 memcpy(pk.pk_lmhash, lmhash, SMBIOC_HASH_SZ); 82 memcpy(pk.pk_nthash, nthash, SMBIOC_HASH_SZ); 83 /* FALLTHROUGH */ 84 85 case SMBIOC_PK_CHK: 86 case SMBIOC_PK_DEL: 87 /* 88 * Copy domain and user. 89 */ 90 if (dom == NULL) { 91 err = SMB_KEYCHAIN_BADDOMAIN; 92 goto out; 93 } 94 sz = sizeof (pk.pk_dom); 95 if (strlcpy(pk.pk_dom, dom, sz) >= sz) { 96 err = SMB_KEYCHAIN_BADDOMAIN; 97 goto out; 98 } 99 if (usr == NULL) { 100 err = SMB_KEYCHAIN_BADUSER; 101 goto out; 102 } 103 sz = sizeof (pk.pk_usr); 104 if (strlcpy(pk.pk_usr, usr, sz) >= sz) { 105 err = SMB_KEYCHAIN_BADUSER; 106 goto out; 107 } 108 break; 109 110 case SMBIOC_PK_DEL_OWNER: /* all owned by the caller */ 111 case SMBIOC_PK_DEL_EVERYONE: /* all owned by everyone */ 112 /* 113 * These two do not copyin any args, but we'll 114 * pass pk here anyway just so we can use the 115 * common code path below. 116 */ 117 break; 118 119 default: 120 err = SMB_KEYCHAIN_UNKNOWN; 121 goto out; 122 } 123 124 fd = smb_open_driver(); 125 if (fd < 0) { 126 err = SMB_KEYCHAIN_NODRIVER; 127 goto out; 128 } 129 130 err = 0; 131 if (ioctl(fd, cmd, &pk) < 0) { 132 err = errno; 133 goto out; 134 } 135 136 if (cmd == SMBIOC_PK_CHK) { 137 if (lmhash != NULL) 138 memcpy(lmhash, pk.pk_lmhash, SMBIOC_HASH_SZ); 139 if (nthash != NULL) 140 memcpy(nthash, pk.pk_nthash, SMBIOC_HASH_SZ); 141 } 142 143 out: 144 if (fd != -1) 145 close(fd); 146 147 return (err); 148 } 149 150 /* 151 * Add a password to the keychain. 152 * 153 * Note: pass is a cleartext password. 154 * We use it here to compute the LM hash and NT hash, 155 * and then store ONLY the hashes. 156 */ 157 int 158 smbfs_keychain_add(uid_t uid, const char *dom, const char *usr, 159 const char *pass) 160 { 161 uchar_t lmhash[SMBIOC_HASH_SZ]; 162 uchar_t nthash[SMBIOC_HASH_SZ]; 163 int err, cmd = SMBIOC_PK_ADD; 164 165 if (pass == NULL) 166 return (SMB_KEYCHAIN_BADPASSWD); 167 168 if ((err = ntlm_compute_lm_hash(lmhash, pass)) != 0) 169 return (err); 170 if ((err = ntlm_compute_nt_hash(nthash, pass)) != 0) 171 return (err); 172 173 err = smbfs_keychain_cmn(cmd, uid, dom, usr, lmhash, nthash); 174 return (err); 175 } 176 177 /* Variant of the above that takes an NT hash. */ 178 int 179 smbfs_keychain_addhash(uid_t uid, const char *dom, const char *usr, 180 const uchar_t *nthash) 181 { 182 static const uchar_t lmhash[SMBIOC_HASH_SZ] = { 0 }; 183 int err, cmd = SMBIOC_PK_ADD; 184 err = smbfs_keychain_cmn(cmd, uid, dom, usr, 185 (uchar_t *)lmhash, (uchar_t *)nthash); 186 return (err); 187 } 188 189 /* Delete a password from the keychain. */ 190 int 191 smbfs_keychain_del(uid_t uid, const char *dom, const char *usr) 192 { 193 return (smbfs_keychain_cmn(SMBIOC_PK_DEL, uid, dom, usr, NULL, NULL)); 194 } 195 196 /* 197 * Check for existence of a keychain entry. 198 * Returns 0 if it exists, else ENOENT. 199 */ 200 int 201 smbfs_keychain_chk(const char *dom, const char *usr) 202 { 203 uid_t uid = (uid_t)-1; 204 return (smbfs_keychain_cmn(SMBIOC_PK_CHK, uid, dom, usr, NULL, NULL)); 205 } 206 207 /* 208 * Get the stored hashes 209 */ 210 int 211 smbfs_keychain_get(const char *dom, const char *usr, 212 uchar_t *lmhash, uchar_t *nthash) 213 { 214 uid_t uid = (uid_t)-1; 215 int err, cmd = SMBIOC_PK_CHK; 216 217 err = smbfs_keychain_cmn(cmd, uid, dom, usr, lmhash, nthash); 218 return (err); 219 } 220 221 /* 222 * Delete all keychain entries owned by the caller. 223 */ 224 int 225 smbfs_keychain_del_owner() 226 { 227 int cmd = SMBIOC_PK_DEL_OWNER; 228 uid_t uid = getuid(); 229 return (smbfs_keychain_cmn(cmd, uid, NULL, NULL, NULL, NULL)); 230 } 231 232 /* 233 * Delete all keychain entries (regardless of onwer). 234 * Requires super-user privliege. 235 */ 236 int 237 smbfs_keychain_del_everyone() 238 { 239 int cmd = SMBIOC_PK_DEL_EVERYONE; 240 uid_t uid = getuid(); 241 return (smbfs_keychain_cmn(cmd, uid, NULL, NULL, NULL, NULL)); 242 } 243 244 /* 245 * Private function to get keychain p/w hashes. 246 */ 247 int 248 smb_get_keychain(struct smb_ctx *ctx) 249 { 250 int err; 251 252 if (ctx->ct_fullserver == NULL) { 253 DPRINT("ct_fullserver == NULL"); 254 return (EINVAL); 255 } 256 257 /* 258 * 1st: try lookup using system name 259 */ 260 err = smbfs_keychain_get(ctx->ct_fullserver, ctx->ct_user, 261 ctx->ct_lmhash, ctx->ct_nthash); 262 if (!err) { 263 ctx->ct_flags |= SMBCF_KCFOUND; 264 DPRINT("found keychain entry for" 265 " server/user: %s/%s\n", 266 ctx->ct_fullserver, ctx->ct_user); 267 return (0); 268 } 269 270 /* 271 * 2nd: try lookup using domain name 272 */ 273 err = smbfs_keychain_get(ctx->ct_domain, ctx->ct_user, 274 ctx->ct_lmhash, ctx->ct_nthash); 275 if (!err) { 276 ctx->ct_flags |= (SMBCF_KCFOUND | SMBCF_KCDOMAIN); 277 DPRINT("found keychain entry for" 278 " domain/user: %s/%s\n", 279 ctx->ct_domain, ctx->ct_user); 280 return (0); 281 } 282 283 return (err); 284 } 285 286 287 /* 288 * This is not really part of the keychain library, 289 * but is typically needed in code that wants to 290 * provide (editable) defaults for domain/user 291 * 292 * Get default domain and user names 293 * Server name is optional. 294 */ 295 int 296 smbfs_default_dom_usr(const char *home, const char *server, 297 char *dom, int maxdom, char *usr, int maxusr) 298 { 299 struct smb_ctx *ctx; 300 int err; 301 302 err = smb_ctx_alloc(&ctx); 303 if (err) 304 return (err); 305 306 if (server) { 307 err = smb_ctx_setfullserver(ctx, server); 308 if (err != 0) 309 goto out; 310 } 311 312 if (home && *home) { 313 if (ctx->ct_home) 314 free(ctx->ct_home); 315 ctx->ct_home = strdup(home); 316 } 317 318 err = smb_ctx_readrc(ctx); 319 if (err) 320 goto out; 321 322 if (dom) 323 strlcpy(dom, ctx->ct_domain, maxdom); 324 325 if (usr) 326 strlcpy(usr, ctx->ct_user, maxusr); 327 328 out: 329 smb_ctx_free(ctx); 330 return (err); 331 } 332