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