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
smbfs_keychain_cmn(int cmd,uid_t uid,const char * dom,const char * usr,uchar_t * lmhash,uchar_t * nthash)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
smbfs_keychain_add(uid_t uid,const char * dom,const char * usr,const char * pass)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
smbfs_keychain_del(uid_t uid,const char * dom,const char * usr)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
smbfs_keychain_chk(const char * dom,const char * usr)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
smbfs_keychain_get(const char * dom,const char * usr,uchar_t * lmhash,uchar_t * nthash)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
smbfs_keychain_del_owner()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
smbfs_keychain_del_everyone()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
smb_get_keychain(struct smb_ctx * ctx)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
smbfs_default_dom_usr(const char * home,const char * server,char * dom,int maxdom,char * usr,int maxusr)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