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