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