Roughly prototype the kauth directory
[openafs.git] / src / kauth / user.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /* This file provides the easiest, turn-key interface to the authication
11  * package. */
12
13 #include <afsconfig.h>
14 #if defined(UKERNEL)
15 #include "afs/param.h"
16 #else
17 #include <afs/param.h>
18 #endif
19
20
21 #if defined(UKERNEL)
22 #include "afs/sysincludes.h"
23 #include "afsincludes.h"
24 #include "afs/stds.h"
25 #include "afs/com_err.h"
26 #include "afs/cellconfig.h"
27 #include "afs/auth.h"
28 #include "afs/ptint.h"
29 #include "afs/pterror.h"
30 #include "afs/ptserver.h"
31 #include "rx/rx.h"
32 #include "rx/rx_globals.h"
33 #include "rx/rxkad.h"
34 #include "afs/kauth.h"
35 #include "afs/kautils.h"
36 #include "afs/afsutil.h"
37 #else /* defined(UKERNEL) */
38 #include <afs/stds.h>
39 #include <signal.h>
40 #include <afs/com_err.h>
41 #ifdef AFS_NT40_ENV
42 #include <winsock2.h>
43 #else
44 #include <netinet/in.h>
45 #include <unistd.h>
46 #endif
47 #include <string.h>
48 #include <afs/cellconfig.h>
49 #include <afs/auth.h>
50 #include <afs/ptint.h>
51 #include <afs/pterror.h>
52 #include <afs/ptuser.h>
53 #include <afs/ptserver.h>
54 #include <afs/afsutil.h>
55 #include <rx/rx.h>
56 #include <rx/rx_globals.h>
57 #include <rx/rxkad.h>           /* max ticket lifetime */
58 #include <des.h>
59 #include <des_prototypes.h>
60 #include "kauth.h"
61 #include "kautils.h"
62 #endif /* defined(UKERNEL) */
63
64
65 afs_int32
66 GetTickets(char *name, char *instance, char *realm,
67            struct ktc_encryptionKey * key, Date lifetime,
68            afs_int32 * pwexpires, afs_int32 flags)
69 {
70     afs_int32 code;
71
72     code = ka_GetAuthToken(name, instance, realm, key, lifetime, pwexpires);
73     memset(key, 0, sizeof(*key));
74     if (code)
75         return code;
76     code = ka_GetAFSTicket(name, instance, realm, lifetime, flags);
77     return code;
78 }
79
80 /* 
81  * Requires that you already possess a TGT.
82  */
83 afs_int32
84 ka_GetAFSTicket(char *name, char *instance, char *realm, Date lifetime,
85                 afs_int32 flags)
86 {
87     afs_int32 code;
88     struct ktc_token token;
89     struct ktc_principal server, client;
90
91     code = ka_GetServerToken("afs", "", realm, lifetime, &token, /*new */ 1,
92                              /*dosetpag */ flags);
93     if (code)
94         return code;
95     if (ktc_OldPioctl()) {
96         int local;
97         char username[MAXKTCNAMELEN];
98         afs_int32 viceId;
99         int len;
100         char *whoami = "UserAuthenticate: ptserver";
101
102         strcpy(server.name, "afs");
103         strcpy(server.instance, "");
104         code = ka_ExpandCell(realm, server.cell, &local);
105         if (code)
106             return code;
107         code = pr_Initialize(0, AFSDIR_CLIENT_ETC_DIRPATH, server.cell);
108         if (code) {
109             afs_com_err(whoami, code, "initializing ptserver in cell '%s'",
110                     server.cell);
111             return 0;
112         }
113         len = strlen(name);
114         if (instance[0])
115             len += strlen(instance) + 1;
116         if (len >= sizeof(username)) {
117             fprintf(stderr, "user's name '%s'.'%s' would be too large\n",
118                     name, instance);
119             return 0;
120         }
121         strcpy(username, name);
122         if (instance[0]) {
123             strcat(username, ".");
124             strcat(username, instance);
125         }
126         code = pr_SNameToId(username, &viceId);
127         /* Before going further, shutdown the pr ubik connection */
128         pr_End();
129         if ((code == 0) && (viceId == ANONYMOUSID))
130             code = PRNOENT;
131         if (code) {
132             afs_com_err(whoami, code, "translating %s to id", username);
133             return 0;
134         }
135
136         sprintf(client.name, "AFS ID %d", viceId);
137         strcpy(client.instance, "");
138         strcpy(client.cell, server.cell);
139         code = ktc_SetToken(&server, &token, &client, /*dosetpag */ 0);
140         if (code)
141             return code;
142     }
143     return code;
144 }
145
146 #ifdef ka_UserAuthenticate
147 #undef ka_UserAuthenticate
148 #endif
149
150 afs_int32
151 ka_UserAuthenticateGeneral(afs_int32 flags, char *name, char *instance, 
152                            char *realm, char *password, Date lifetime, 
153                            afs_int32 * password_expires,        /* days 'til, or don't change if not set */
154                            afs_int32 spare2, char **reasonP)
155 {
156     int remainingTime = 0;
157     struct ktc_encryptionKey key;
158     afs_int32 code, dosetpag = 0;
159 #if !defined(AFS_NT40_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_USR_LINUX20_ENV) && !defined(AFS_XBSD_ENV) || defined(AFS_FBSD_ENV)
160     sig_t old;
161 #endif
162
163     if (reasonP)
164         *reasonP = "";
165     if ((flags & KA_USERAUTH_VERSION_MASK) != KA_USERAUTH_VERSION)
166         return KAOLDINTERFACE;
167     if ((strcmp(name, "root") == 0) && (instance == 0)) {
168         if (reasonP)
169             *reasonP = "root is only authenticated locally";
170         return KANOENT;
171     }
172     code = ka_Init(0);
173     if (code)
174         return code;
175
176     ka_StringToKey(password, realm, &key);
177
178 /* 
179  * alarm is set by klogin and kpasswd only so ignore for
180  * NT
181  */
182
183 #ifndef AFS_NT40_ENV
184     {                           /* Rx uses timers, save to be safe */
185         if (rx_socket) {
186             /* don't reset alarms, rx already running */
187             remainingTime = 0;
188         } else
189             remainingTime = alarm(0);
190     }
191 #endif
192
193 #if !defined(AFS_NT40_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_USR_LINUX20_ENV) && (!defined(AFS_XBSD_ENV) || defined(AFS_FBSD_ENV))
194     /* handle smoothly the case where no AFS system calls exists (yet) */
195     old = signal(SIGSYS, SIG_IGN);
196 #endif
197 #ifdef  AFS_DECOSF_ENV
198     (void)signal(SIGTRAP, SIG_IGN);
199 #endif /* AFS_DECOSF_ENV */
200     if (instance == 0)
201         instance = "";
202     if (flags & KA_USERAUTH_ONLY_VERIFY) {
203         code = ka_VerifyUserToken(name, instance, realm, &key);
204         if (code == KABADREQUEST) {
205             des_string_to_key(password, &key);
206             code = ka_VerifyUserToken(name, instance, realm, &key);
207         }
208     } else {
209 #ifdef AFS_DUX40_ENV
210         if (flags & KA_USERAUTH_DOSETPAG)
211             afs_setpag();
212 #else
213 #if !defined(UKERNEL) && !defined(AFS_NT40_ENV)
214         if (flags & KA_USERAUTH_DOSETPAG)
215             setpag();
216 #endif
217 #endif
218         if (flags & KA_USERAUTH_DOSETPAG2)
219             dosetpag = 1;
220 #ifdef AFS_KERBEROS_ENV
221         if ((flags & KA_USERAUTH_DOSETPAG) || dosetpag)
222             ktc_newpag();
223 #endif
224         if (lifetime == 0)
225             lifetime = MAXKTCTICKETLIFETIME;
226         code =
227             GetTickets(name, instance, realm, &key, lifetime,
228                        password_expires, dosetpag);
229         if (code == KABADREQUEST) {
230             des_string_to_key(password, &key);
231             code =
232                 GetTickets(name, instance, realm, &key, lifetime,
233                            password_expires, dosetpag);
234         }
235
236 /* By the time 3.3 comes out, these "old-style" passwd programs should be 
237  * well and truly obsolete.  Any passwords set with such a program
238  * OUGHT to have been changed years ago.  Having 2 -or- 3
239  * authentication RPCs generated for every klog plays hob with the
240  * "failed login limits" code in the kaserver, and it's hard to
241  * explain to admins just how to set the limit properly.  By removing 
242  * this function, we can just double it internally in the kaserver, and 
243  * not document anything.  kpasswd had the TRUNCATEPASSWORD "feature"
244  * disabled on 10/02/90.
245  */
246 #ifdef OLDCRUFT
247         if ((code == KABADREQUEST) && (strlen(password) > 8)) {
248             /* try with only the first 8 characters incase they set their password
249              * with an old style passwd program. */
250             char pass8[9];
251             strncpy(pass8, password, 8);
252             pass8[8] = 0;
253             ka_StringToKey(pass8, realm, &key);
254             memset(pass8, 0, sizeof(pass8));
255             code =
256                 GetTickets(name, instance, realm, &key, lifetime,
257                            password_expires, dosetpag);
258             if (code == 0) {
259                 fprintf(stderr, "%s %s\n%s %s\n%s\n",
260                         "Warning: you have typed a password longer than 8",
261                         "characters, but only the",
262                         "first 8 characters were actually significant.  If",
263                         "you change your password",
264                         "again this warning message will go away.\n");
265             }
266         }
267 #endif /* OLDCRUFT */
268     }
269
270 #ifndef AFS_NT40_ENV
271     if (remainingTime) {
272         pr_End();
273         rx_Finalize();
274         alarm(remainingTime);   /* restore timer, if any */
275     }
276 #endif
277
278     if (code && reasonP)
279         switch (code) {
280         case KABADREQUEST:
281             *reasonP = "password was incorrect";
282             break;
283         case KAUBIKCALL:
284             *reasonP = "Authentication Server was unavailable";
285             break;
286         default:
287             *reasonP = (char *)afs_error_message(code);
288         }
289     return code;
290 }
291
292 /* For backward compatibility */
293 afs_int32
294 ka_UserAuthenticate(char *name, char *instance, char *realm, char *password,
295                     int doSetPAG, char **reasonP)
296 {
297     return ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION +
298                                       ((doSetPAG) ? KA_USERAUTH_DOSETPAG : 0),
299                                       name, instance, realm, password,
300                                       /*lifetime */ 0, /*spare1,2 */ 0, 0,
301                                       reasonP);
302 }
303
304 #if !defined(UKERNEL)
305 afs_int32
306 ka_UserReadPassword(char *prompt, char *password, int plen, char **reasonP)
307 {
308     afs_int32 code = 0;
309
310     if (reasonP)
311         *reasonP = "";
312     code = ka_Init(0);
313     if (code)
314         return code;
315     code = read_pw_string(password, plen, prompt, 0);
316     if (code)
317         code = KAREADPW;
318     else if (strlen(password) == 0)
319         code = KANULLPASSWORD;
320     else
321         return 0;
322
323     if (reasonP) {
324         *reasonP = (char *)afs_error_message(code);
325     }
326     return code;
327 }
328 #endif /* !defined(UKERNEL) */
329
330 afs_int32
331 ka_VerifyUserPassword(afs_int32 version, char *name, char *instance,
332                       char *realm, char *password, int spare, char **reasonP)
333 {
334     afs_int32 pwexpires;
335
336     version &= KA_USERAUTH_VERSION_MASK;
337     return ka_UserAuthenticateGeneral(version | KA_USERAUTH_ONLY_VERIFY, name,
338                                       instance, realm, password, 0,
339                                       &pwexpires, spare, reasonP);
340 }