auth-cleanup-20070208
[openafs.git] / src / kauth / klog.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 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID
14     ("$Header$");
15
16 #include <afs/stds.h>
17 #include <sys/types.h>
18 #include <rx/xdr.h>
19 #ifdef  AFS_AIX32_ENV
20 #include <signal.h>
21 #endif
22 #ifdef HAVE_STRING_H
23 #include <string.h>
24 #else
25 #ifdef HAVE_STRINGS_H
26 #include <strings.h>
27 #endif
28 #endif
29
30 #include <lock.h>
31 #include <ubik.h>
32
33 #include <stdio.h>
34 #include <pwd.h>
35 #include <afs/com_err.h>
36 #include <afs/cellconfig.h>
37 #include <afs/cmd.h>
38 #include "kauth.h"
39 #include "kautils.h"
40 #include "assert.h"
41
42
43 /* This code borrowed heavily from the previous version of log.  Here is the
44    intro comment for that program: */
45
46 /*
47         log -- tell the Andrew Cache Manager your password
48         5 June 1985
49         modified
50         February 1986
51
52         Further modified in August 1987 to understand cell IDs.
53  */
54
55 /* Current Usage:
56      klog [principal [password]] [-t] [-c cellname] [-servers <hostlist>]
57
58      where:
59        principal is of the form 'name' or 'name@cell' which provides the
60           cellname.  See the -c option below.
61        password is the user's password.  This form is NOT recommended for
62           interactive users.
63        -t advises klog to write a Kerberos style ticket file in /tmp.
64        -c identifies cellname as the cell in which authentication is to take
65           place.
66        -servers allows the explicit specification of the hosts providing
67           authentication services for the cell being used for authentication.
68  */
69
70 #define KLOGEXIT(code) assert(!code || code >= KAMINERROR); \
71                        rx_Finalize(); \
72                        (!code ? exit(0) : exit((code)-KAMINERROR+1))
73 extern int CommandProc(struct cmd_syndesc *as, char *arock);
74
75 static int zero_argc;
76 static char **zero_argv;
77
78 int
79 osi_audit(void)
80 {
81     return 0;
82 }
83
84 int
85 main(int argc, char *argv[])
86 {
87     struct cmd_syndesc *ts;
88     afs_int32 code;
89 #ifdef  AFS_AIX32_ENV
90     /*
91      * The following signal action for AIX is necessary so that in case of a 
92      * crash (i.e. core is generated) we can include the user's data section 
93      * in the core dump. Unfortunately, by default, only a partial core is
94      * generated which, in many cases, isn't too useful.
95      */
96     struct sigaction nsa;
97
98     sigemptyset(&nsa.sa_mask);
99     nsa.sa_handler = SIG_DFL;
100     nsa.sa_flags = SA_FULLDUMP;
101     sigaction(SIGABRT, &nsa, NULL);
102     sigaction(SIGSEGV, &nsa, NULL);
103 #endif
104     zero_argc = argc;
105     zero_argv = argv;
106
107     ts = cmd_CreateSyntax(NULL, CommandProc, 0,
108                           "obtain Kerberos authentication");
109
110 #define aXFLAG 0
111 #define aPRINCIPAL 1
112 #define aPASSWORD 2
113 #define aCELL 3
114 #define aSERVERS 4
115 #define aPIPE 5
116 #define aSILENT 6
117 #define aLIFETIME 7
118 #define aSETPAG 8
119 #define aTMP 9
120
121
122     cmd_AddParm(ts, "-x", CMD_FLAG, CMD_OPTIONAL, "(obsolete, noop)");
123     cmd_Seek(ts, aPRINCIPAL);
124     cmd_AddParm(ts, "-principal", CMD_SINGLE, CMD_OPTIONAL, "user name");
125     cmd_AddParm(ts, "-password", CMD_SINGLE, CMD_OPTIONAL, "user's password");
126     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
127     cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL,
128                 "explicit list of servers");
129     cmd_AddParm(ts, "-pipe", CMD_FLAG, CMD_OPTIONAL,
130                 "read password from stdin");
131     cmd_AddParm(ts, "-silent", CMD_FLAG, CMD_OPTIONAL, "silent operation");
132     cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL,
133                 "ticket lifetime in hh[:mm[:ss]]");
134     cmd_AddParm(ts, "-setpag", CMD_FLAG, CMD_OPTIONAL,
135                 "Create a new setpag before authenticating");
136     cmd_AddParm(ts, "-tmp", CMD_FLAG, CMD_OPTIONAL,
137                 "write Kerberos-style ticket file in /tmp");
138
139     code = cmd_Dispatch(argc, argv);
140     KLOGEXIT(code);
141 }
142
143 static char *
144 getpipepass(void)
145 {
146     static char gpbuf[BUFSIZ];
147     /* read a password from stdin, stop on \n or eof */
148     register int i, tc;
149     memset(gpbuf, 0, sizeof(gpbuf));
150     for (i = 0; i < (sizeof(gpbuf) - 1); i++) {
151         tc = fgetc(stdin);
152         if (tc == '\n' || tc == EOF)
153             break;
154         gpbuf[i] = tc;
155     }
156     return gpbuf;
157 }
158
159 int
160 CommandProc(struct cmd_syndesc *as, char *arock)
161 {
162     char name[MAXKTCNAMELEN];
163     char instance[MAXKTCNAMELEN];
164     char cell[MAXKTCREALMLEN];
165     char realm[MAXKTCREALMLEN];
166     afs_int32 serverList[MAXSERVERS];
167     char *lcell;                /* local cellname */
168     char lrealm[MAXKTCREALMLEN];        /* uppercase copy of local cellname */
169     int code;
170     int i, dosetpag;
171     Date lifetime;              /* requested ticket lifetime */
172
173     struct passwd pwent;
174     struct passwd *pw = &pwent;
175     struct passwd *lclpw = &pwent;
176     char passwd[BUFSIZ];
177
178     static char rn[] = "klog";  /*Routine name */
179     static int Pipe = 0;        /* reading from a pipe */
180     static int Silent = 0;      /* Don't want error messages */
181
182     int explicit;               /* servers specified explicitly */
183     int local;                  /* explicit cell is same a local one */
184     int foundPassword = 0;      /*Not yet, anyway */
185     int foundExplicitCell = 0;  /*Not yet, anyway */
186     int writeTicketFile = 0;    /* write ticket file to /tmp */
187     afs_int32 password_expires = -1;
188
189     char *reason;               /* string describing errors */
190
191     /* blow away command line arguments */
192     for (i = 1; i < zero_argc; i++)
193         memset(zero_argv[i], 0, strlen(zero_argv[i]));
194     zero_argc = 0;
195
196     /* first determine quiet flag based on -silent switch */
197     Silent = (as->parms[aSILENT].items ? 1 : 0);
198     Pipe = (as->parms[aPIPE].items ? 1 : 0);
199
200     /* Determine if we should also do a setpag based on -setpag switch */
201     dosetpag = (as->parms[aSETPAG].items ? 1 : 0);
202
203     if (as->parms[aTMP].items) {
204         writeTicketFile = 1;
205     }
206
207     if (as->parms[aCELL].items) {
208         /*
209          * cell name explicitly mentioned; take it in if no other cell name
210          * has already been specified and if the name actually appears.  If
211          * the given cell name differs from our own, we don't do a lookup.
212          */
213         foundExplicitCell = 1;
214         strncpy(realm, as->parms[aCELL].items->data, sizeof(realm));
215         /* XXX the following is just a hack to handle the afscell environment XXX */
216         (void)afsconf_GetCellInfo((struct afsconf_dir *)0, realm, 0,
217                                   (struct afsconf_cell *)0);
218     }
219
220     code = ka_Init(0);
221     if (code || !(lcell = ka_LocalCell())) {
222       nocell:
223         if (!Silent)
224             com_err(rn, code, "Can't get local cell name!");
225         KLOGEXIT(code);
226     }
227     if (code = ka_CellToRealm(lcell, lrealm, 0))
228         goto nocell;
229
230     strcpy(instance, "");
231
232     /* Parse our arguments. */
233
234     if (as->parms[aCELL].items) {
235         /*
236          * cell name explicitly mentioned; take it in if no other cell name
237          * has already been specified and if the name actually appears.  If
238          * the given cell name differs from our own, we don't do a lookup.
239          */
240         foundExplicitCell = 1;
241         strncpy(realm, as->parms[aCELL].items->data, sizeof(realm));
242     }
243
244     if (as->parms[aSERVERS].items) {
245         /* explicit server list */
246         int i;
247         struct cmd_item *ip;
248         char *ap[MAXSERVERS + 2];
249
250         for (ip = as->parms[aSERVERS].items, i = 2; ip; ip = ip->next, i++)
251             ap[i] = ip->data;
252         ap[0] = "";
253         ap[1] = "-servers";
254         code = ubik_ParseClientList(i, ap, serverList);
255         if (code) {
256             if (!Silent) {
257                 com_err(rn, code, "could not parse server list");
258             }
259             return code;
260         }
261         explicit = 1;
262     } else
263         explicit = 0;
264
265     if (as->parms[aPRINCIPAL].items) {
266         ka_ParseLoginName(as->parms[aPRINCIPAL].items->data, name, instance,
267                           cell);
268         if (strlen(instance) > 0)
269             if (!Silent) {
270                 fprintf(stderr,
271                         "Non-null instance (%s) may cause strange behavior.\n",
272                         instance);
273             }
274         if (strlen(cell) > 0) {
275             if (foundExplicitCell) {
276                 if (!Silent) {
277                     fprintf(stderr,
278                             "%s: May not specify an explicit cell twice.\n",
279                             rn);
280                 }
281                 return -1;
282             }
283             foundExplicitCell = 1;
284             strncpy(realm, cell, sizeof(realm));
285         }
286         lclpw->pw_name = name;
287     } else {
288         /* No explicit name provided: use Unix uid. */
289         pw = getpwuid(getuid());
290         if (pw == 0) {
291             if (!Silent) {
292                 fprintf(stderr,
293                         "Can't figure out your name in local cell %s from your user id.\n",
294                         lcell);
295                 fprintf(stderr, "Try providing the user name.\n");
296             }
297             KLOGEXIT(KABADARGUMENT);
298         }
299         lclpw = pw;
300     }
301
302     if (as->parms[aPASSWORD].items) {
303         /*
304          * Current argument is the desired password string.  Remember it in
305          * our local buffer, and zero out the argument string - anyone can
306          * see it there with ps!
307          */
308         foundPassword = 1;
309         strncpy(passwd, as->parms[aPASSWORD].items->data, sizeof(passwd));
310         memset(as->parms[aPASSWORD].items->data, 0,
311                strlen(as->parms[aPASSWORD].items->data));
312     }
313
314     if (as->parms[aLIFETIME].items) {
315         char *life = as->parms[aLIFETIME].items->data;
316         char *sp;               /* string ptr to rest of life */
317         lifetime = 3600 * strtol(life, &sp, 0); /* hours */
318         if (sp == life) {
319           bad_lifetime:
320             if (!Silent)
321                 fprintf(stderr, "%s: translating '%s' to lifetime failed\n",
322                         rn, life);
323             return KABADARGUMENT;
324         }
325         if (*sp == ':') {
326             life = sp + 1;      /* skip the colon */
327             lifetime += 60 * strtol(life, &sp, 0);      /* minutes */
328             if (sp == life)
329                 goto bad_lifetime;
330             if (*sp == ':') {
331                 life = sp + 1;
332                 lifetime += strtol(life, &sp, 0);       /* seconds */
333                 if (sp == life)
334                     goto bad_lifetime;
335                 if (*sp)
336                     goto bad_lifetime;
337             } else if (*sp)
338                 goto bad_lifetime;
339         } else if (*sp)
340             goto bad_lifetime;
341         if (lifetime > MAXKTCTICKETLIFETIME) {
342             if (!Silent)
343                 fprintf(stderr,
344                         "%s: a lifetime of %.2f hours is too long, must be less than %d.\n",
345                         rn, (double)lifetime / 3600.0,
346                         MAXKTCTICKETLIFETIME / 3600);
347             KLOGEXIT(KABADARGUMENT);
348         }
349     } else
350         lifetime = 0;
351
352     if (!foundExplicitCell)
353         strcpy(realm, lcell);
354     if (code = ka_CellToRealm(realm, realm, &local)) {
355         if (!Silent)
356             com_err(rn, code, "Can't convert cell to realm");
357         KLOGEXIT(code);
358     }
359
360     /* Get the password if it wasn't provided. */
361     if (!foundPassword) {
362         if (Pipe) {
363             strncpy(passwd, getpipepass(), sizeof(passwd));
364         } else {
365             if (ka_UserReadPassword
366                 ("Password:", passwd, sizeof(passwd), &reason)) {
367                 fprintf(stderr, "Unable to login because %s.\n", reason);
368                 KLOGEXIT(KABADARGUMENT);
369             }
370         }
371     }
372
373     if (explicit)
374         ka_ExplicitCell(realm, serverList);
375
376     code =
377         ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION +
378                                    (dosetpag ? KA_USERAUTH_DOSETPAG2 : 0),
379                                    pw->pw_name, instance, realm, passwd,
380                                    lifetime, &password_expires, 0, &reason);
381     memset(passwd, 0, sizeof(passwd));
382     if (code) {
383         if (!Silent) {
384             fprintf(stderr, "Unable to authenticate to AFS because %s.\n",
385                     reason);
386         }
387         KLOGEXIT(code);
388     }
389 #ifndef AFS_KERBEROS_ENV
390     if (writeTicketFile) {
391         code = krb_write_ticket_file(realm);
392         if (!Silent) {
393             if (code)
394                 com_err(rn, code, "writing Kerberos ticket file");
395             else
396                 fprintf(stderr, "Wrote ticket file to /tmp\n");
397         }
398     }
399 #endif
400
401 #ifdef DEBUGEXPIRES
402     if (password_expires >= 0) {
403         printf("password expires at %ld\n", password_expires);
404     }
405 #endif /* DEBUGEXPIRES */
406
407     return 0;
408 }