2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afs/param.h>
14 #include <afs/kautils.h>
15 #include <afs/dirpath.h>
16 #include "cm_config.h"
20 #define AFS_KERBEROS_ENV
22 #define BAD_ARGUMENT 1
23 #define KLOGEXIT(code) exit(code)
25 static int CommandProc(struct cmd_syndesc *, void *);
28 static char **zero_argv;
30 void main (argc, argv)
33 { struct cmd_syndesc *ts;
40 /* Start up sockets */
41 WSAStartup(0x0101, &WSAjunk);
43 ts = cmd_CreateSyntax(NULL, CommandProc, NULL, "obtain Kerberos authentication");
57 cmd_AddParm(ts, "-x", CMD_FLAG, CMD_OPTIONAL, "(obsolete, noop)");
58 cmd_Seek(ts, aPRINCIPAL);
59 cmd_AddParm(ts, "-principal", CMD_SINGLE, CMD_OPTIONAL, "user name");
60 cmd_AddParm(ts, "-password", CMD_SINGLE, CMD_OPTIONAL, "user's password");
61 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
62 cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL, "explicit list of servers");
63 cmd_AddParm(ts, "-pipe", CMD_FLAG, CMD_OPTIONAL, "read password from stdin");
64 cmd_AddParm(ts, "-silent", CMD_FLAG, CMD_OPTIONAL, "silent operation");
65 cmd_AddParm(ts, "-lifetime", CMD_SINGLE, CMD_OPTIONAL, "ticket lifetime in hh[:mm[:ss]]");
66 cmd_AddParm(ts, "-setpag", CMD_FLAG, CMD_OPTIONAL, "Create a new setpag before authenticating");
67 cmd_AddParm(ts, "-tmp", CMD_FLAG, CMD_OPTIONAL, "write Kerberos-style ticket file in /tmp");
69 code = cmd_Dispatch(argc, argv);
73 static char *getpipepass() {
74 static char gpbuf[BUFSIZ];
75 /* read a password from stdin, stop on \n or eof */
77 memset(gpbuf, 0, sizeof(gpbuf));
78 for(i=0; i<(sizeof(gpbuf)-1); i++) {
80 if (tc == '\n' || tc == EOF) break;
86 /* good_gets is like gets except that it take a max string length and won't
87 * write past the end of its input buffer. It returns a variety of negative
88 * numbers in case of errors and zero if there was no characters read (a blank
89 * line for instance). Otherwise it returns the length of the string read in.
92 static int good_gets (s, max)
95 { int l; /* length of string read */
96 if (!fgets (s, max, stdin)) {
97 if (feof(stdin)) return EOF; /* EOF on input, nothing read */
98 else return -2; /* I don't think this can happen */
101 if (l && (s[l-1] == '\n')) s[--l] = 0;
105 static int read_pw_string(char *s, int max)
112 h = GetStdHandle (STD_INPUT_HANDLE);
113 GetConsoleMode (h, &md);
114 SetConsoleMode (h, md & ~ENABLE_ECHO_INPUT);
119 if (good_gets(s, max) <= 0) {
120 printf("\n"); fflush(stdout);
121 if (feof (stdin)) break; /* just give up */
122 else continue; /* try again: blank line */
131 SetConsoleMode (h, md);
132 printf("\n"); fflush(stdout);
134 s[max-1] = 0; /* force termination */
139 CommandProc (struct cmd_syndesc *as, void *arock)
141 char name[MAXKTCNAMELEN];
142 char instance[MAXKTCNAMELEN];
143 char cell[MAXKTCREALMLEN];
144 char defaultCell[256];
145 char realm[MAXKTCREALMLEN];
148 int lifetime; /* requested ticket lifetime */
152 static char rn[] = "klog"; /*Routine name*/
153 static int Pipe = 0; /* reading from a pipe */
154 static int Silent = 0; /* Don't want error messages */
156 int foundPassword = 0; /*Not yet, anyway*/
157 int foundExplicitCell = 0; /*Not yet, anyway*/
158 int writeTicketFile = 0; /* write ticket file to /tmp */
159 int password_expires = -1;
161 char *reason; /* string describing errors */
168 /* blow away command line arguments */
169 for (i=1; i<zero_argc; i++) memset (zero_argv[i], 0, strlen(zero_argv[i]));
172 /* first determine quiet flag based on -silent switch */
173 Silent = (as->parms[aSILENT].items ? 1 : 0);
174 Pipe = (as->parms[aPIPE].items ? 1 : 0);
176 /* Determine if we should also do a setpag based on -setpag switch */
177 dosetpag = (as->parms[aSETPAG].items ? 1 : 0);
179 if (as->parms[aTMP].items) {
183 cm_GetRootCellName(defaultCell);
186 /* Parse our arguments. */
188 if (as->parms[aCELL].items) {
190 * cell name explicitly mentioned; take it in if no other cell name
191 * has already been specified and if the name actually appears. If
192 * the given cell name differs from our own, we don't do a lookup.
194 foundExplicitCell = 1;
195 strncpy (realm, as->parms[aCELL].items->data, sizeof(realm));
198 if (as->parms[aSERVERS].items) {
199 fprintf (stderr, "SERVERS option not available.\n");
202 if (as->parms[aPRINCIPAL].items) {
203 ka_ParseLoginName (as->parms[aPRINCIPAL].items->data,
204 name, instance, cell);
205 if (strlen (instance) > 0)
208 "Non-null instance (%s) may cause strange behavior.\n",
211 if (strlen(cell) > 0) {
212 if (foundExplicitCell) {
215 "%s: May not specify an explicit cell twice.\n", rn);
219 foundExplicitCell = 1;
220 strncpy (realm, cell, sizeof(realm));
223 /* No explicit name provided. */
224 DWORD size = GetEnvironmentVariable("USERNAME", name, sizeof(name) - 1);
225 if (size <= 0 || size >= sizeof(name)) {
226 size = sizeof(name) - 1;
227 if (!GetUserName(name, &size)) {
228 KLOGEXIT( BAD_ARGUMENT );
233 if (as->parms[aPASSWORD].items) {
235 * Current argument is the desired password string. Remember it in
236 * our local buffer, and zero out the argument string - anyone can
237 * see it there with ps!
240 strncpy (passwd, as->parms[aPASSWORD].items->data, sizeof(passwd));
241 memset (as->parms[aPASSWORD].items->data, 0,
242 strlen(as->parms[aPASSWORD].items->data));
245 if (as->parms[aLIFETIME].items) {
246 char *life = as->parms[aLIFETIME].items->data;
247 char *sp; /* string ptr to rest of life */
248 lifetime = 3600*strtol (life, &sp, 0); /* hours */
251 if (!Silent) fprintf (stderr, "%s: translating '%s' to lifetime failed\n",
256 life = sp+1; /* skip the colon */
257 lifetime += 60*strtol (life, &sp, 0); /* minutes */
258 if (sp == life) goto bad_lifetime;
261 lifetime += strtol (life, &sp, 0); /* seconds */
262 if (sp == life) goto bad_lifetime;
263 if (*sp) goto bad_lifetime;
264 } else if (*sp) goto bad_lifetime;
265 } else if (*sp) goto bad_lifetime;
266 if (lifetime > MAXKTCTICKETLIFETIME) {
269 "%s: a lifetime of %.2f hours is too long, must be less than %d.\n",
270 rn, (double)lifetime/3600.0, MAXKTCTICKETLIFETIME/3600);
271 KLOGEXIT( BAD_ARGUMENT );
275 if (!foundExplicitCell) strcpy (realm, defaultCell);
277 /* Get the password if it wasn't provided. */
278 if (!foundPassword) {
280 strncpy(passwd, getpipepass(), sizeof(passwd));
283 if (read_pw_string(passwd, sizeof(passwd)))
284 reason = "can't read password from terminal";
285 else if (strlen(passwd) == 0)
286 reason = "zero length password is illegal";
290 fprintf (stderr, "Unable to login because %s.\n", reason);
291 KLOGEXIT( BAD_ARGUMENT );
296 code = ka_UserAuthenticateGeneral (KA_USERAUTH_VERSION,
297 name, instance, realm, passwd, lifetime,
298 &password_expires, 0, &reason);
299 memset (passwd, 0, sizeof(passwd));
303 "Unable to authenticate to AFS because %s.\n", reason);
308 #ifndef AFS_KERBEROS_ENV
309 if (writeTicketFile) {
310 code = krb_write_ticket_file (realm);
313 afs_com_err (rn, code, "writing Kerberos ticket file");
314 else fprintf (stderr, "Wrote ticket file to /tmp\n");
320 if (password_expires >= 0) {
321 printf ("password expires at %ld\n", password_expires);
323 #endif /* DEBUGEXPIRES */