krb5_passwd.c revision 1.2 1 /* $NetBSD: krb5_passwd.c,v 1.2 1996/08/09 09:19:35 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "from: @(#)krb_passwd.c 5.4 (Berkeley) 3/1/91";
39 #else
40 static char rcsid[] = "$NetBSD: krb5_passwd.c,v 1.2 1996/08/09 09:19:35 thorpej Exp $";
41 #endif
42 #endif /* not lint */
43
44 #ifdef KERBEROS5
45
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <sys/time.h>
49 #include <sys/resource.h>
50 #include <netinet/in.h>
51 #include <netdb.h>
52 #include <signal.h>
53 #include <pwd.h>
54 #include <errno.h>
55 #include <stdio.h>
56 #include <string.h>
57 #include <stdlib.h>
58 #include <krb5/adm_defs.h>
59 #include <krb5/krb5.h>
60 #include <krb5/kdb.h>
61 #include <krb5/kdb_dbm.h>
62 #include <krb5/ext-proto.h>
63 #include <krb5/los-proto.h>
64 #include <krb5/asn1.h>
65 #include <krb5/config.h>
66 #include <krb5/base-defs.h>
67 #include <krb5/asn.1/encode.h>
68
69 #include <krb5/widen.h>
70
71 #include <krb5/adm_err.h>
72 #include <krb5/errors.h>
73 #include <krb5/kdb5_err.h>
74 #include <krb5/krb5_err.h>
75
76 static krb5_error_code get_first_ticket __P((krb5_ccache, krb5_principal));
77 static krb5_error_code print_and_choose_password __P((char *, krb5_data *));
78 static krb5_error_code adm5_init_link __P((krb5_data *, int *));
79
80 struct sockaddr_in local_sin, remote_sin;
81
82 krb5_creds my_creds;
83
84 extern char *krb5_default_pwd_prompt1;
85
86 /*
87 * Try no preauthentication first; then try the encrypted timestamp
88 */
89 int preauth_search_list[] = {
90 0,
91 KRB5_PADATA_ENC_TIMESTAMP,
92 -1
93 };
94
95 krb_passwd()
96 {
97 static void finish();
98 krb5_ccache cache = NULL;
99 char cache_name[255];
100 krb5_flags cc_flags;
101 krb5_address local_addr, foreign_addr;
102 struct passwd *pw;
103 krb5_principal client, server;
104 char default_name[256];
105 char *client_name; /* Single string representation of client id */
106 krb5_data requested_realm;
107 char *local_realm;
108 char input_string[768];
109 krb5_error_code retval; /* return code */
110 int local_socket;
111 int c, count;
112 krb5_error *err_ret;
113 krb5_ap_rep_enc_part *rep_ret;
114 kadmin_requests rd_priv_resp;
115 krb5_checksum send_cksum;
116 int cksum_alloc = 0;
117 krb5_data msg_data, inbuf;
118 krb5_int32 seqno;
119 char *new_password;
120 int new_pwsize;
121 krb5_data *decodable_pwd_string;
122 int i, j;
123 static struct rlimit rl = { 0, 0 };
124
125 #ifdef KRB_NONETWORK
126 extern int networked();
127 int krb_secure;
128 struct stat statbuf;
129 #endif
130
131 #ifdef KRB_NONETWORK /* Allow or Disallow Remote Clients to Modify Passwords */
132 /*
133 * If a Client Modifies a Password using kpasswd on this host
134 * from a remote host or network terminal, the Password selected
135 * is transmitted across the network in Cleartext.
136 *
137 * The systems administrator can disallow "remote" kpasswd usage by
138 * creating the file "/etc/krb.secure"
139 */
140 krb_secure = 0;
141 /*
142 * First check to see if the file /etc/krb.secure exists.
143 * If it does then krb_secure to 1.
144 */
145
146 if (stat("/etc/krb.secure", &statbuf) == 0) krb_secure = 1;
147
148 /*
149 * Check to see if this process is tied to a physical terminal.
150 * Network() verifies the terminal device is not a pseudo tty
151 */
152 if (networked() && krb_secure) {
153 fprintf(stderr,"passwd: Sorry but you cannot %s from a\n", argv[0]);
154 fprintf(stderr," pseudo tty terminal.\n");
155 retval = 1;
156 goto finish;
157 }
158 #endif
159
160 /* (3 * 255) + 1 (/) + 1 (@) + 1 (NULL) */
161 if ((client_name = (char *) calloc (1, (3 * 256))) == NULL) {
162 fprintf(stderr, "passwd: No Memory for Client_name\n");
163 retval = 1;
164 goto finish;
165 }
166
167 if ((requested_realm.data = (char *) calloc (1, 256)) == NULL) {
168 fprintf(stderr, "passwd: No Memory for realm_name\n");
169 retval = 1;
170 free(client_name);
171 goto finish;
172 }
173
174 (void)signal(SIGHUP, SIG_IGN);
175 (void)signal(SIGINT, SIG_IGN);
176 (void)signal(SIGTSTP, SIG_IGN);
177
178 if (setrlimit(RLIMIT_CORE, &rl) < 0) {
179 (void)fprintf(stderr,
180 "passwd: setrlimit: %s\n", strerror(errno));
181 return(1);
182 }
183
184 krb5_init_ets();
185 memset((char *) default_name, 0, sizeof(default_name));
186
187 /* Identify Default Credentials Cache */
188 if ((retval = krb5_cc_default(&cache))) {
189 fprintf(stderr, "passwd: Error while getting default ccache.\n");
190 goto finish;
191 }
192
193 /*
194 * Attempt to Modify Credentials Cache
195 * retval == 0 ==> ccache Exists - Use It
196 * retval == ENOENT ==> No Entries, but ccache Exists
197 * retval != 0 ==> Assume ccache does NOT Exist
198 */
199 cc_flags = 0;
200 if ((retval = krb5_cc_set_flags(cache, cc_flags))) {
201 /* Search passwd file for client */
202 pw = getpwuid((int) getuid());
203 if (pw) {
204 (void) strcpy(default_name, pw->pw_name);
205 }
206 else {
207 fprintf(stderr,
208 "passwd: Unable to Identify Customer from Password File\n");
209 retval = 1;
210 goto finish;
211 }
212
213 /* Use this to get default_realm and format client_name */
214 if ((retval = krb5_parse_name(default_name, &client))) {
215 fprintf(stderr, "passwd: Unable to Parse Client Name\n");
216 goto finish;
217 }
218
219 if ((retval = krb5_unparse_name(client, &client_name))) {
220 fprintf(stderr, "passwd: Unable to Parse Client Name\n");
221 goto finish;
222 }
223
224 requested_realm.length = client->realm.length;
225 memcpy((char *) requested_realm.data,
226 (char *) client->realm.data,
227 requested_realm.length);
228 }
229 else {
230 /* Read Client from Cache */
231 if ((retval = krb5_cc_get_principal(cache, (krb5_principal *) &client))) {
232 fprintf(stderr, "passwd: Unable to Read Customer Credentials File\n");
233 goto finish;
234 }
235
236 if ((retval = krb5_unparse_name(client, &client_name))) {
237 fprintf(stderr, "passwd: Unable to Parse Client Name\n");
238 goto finish;
239 }
240
241 requested_realm.length = client->realm.length;
242 memcpy((char *) requested_realm.data,
243 (char *) client->realm.data,
244 requested_realm.length);
245
246 (void) krb5_cc_close(cache);
247 }
248
249 /* Create credential cache for changepw */
250 (void) sprintf(cache_name, "FILE:/tmp/tkt_cpw_%d", getpid());
251
252 if ((retval = krb5_cc_resolve(cache_name, &cache))) {
253 fprintf(stderr, "passwd: Unable to Resolve Cache: %s\n", cache_name);
254 }
255
256 if ((retval = krb5_cc_initialize(cache, client))) {
257 fprintf(stderr, "passwd: Error initializing cache: %s\n", cache_name);
258 goto finish;
259 }
260
261 /*
262 * Verify User by Obtaining Initial Credentials prior to Initial Link
263 */
264 if ((retval = get_first_ticket(cache, client))) {
265 goto finish;
266 }
267
268 /* Initiate Link to Server */
269 if ((retval = adm5_init_link(&requested_realm, &local_socket))) {
270 goto finish;
271 }
272
273 #define SIZEOF_INADDR sizeof(struct in_addr)
274
275 /* V4 kpasswd Protocol Hack */
276 {
277 int msg_length = 0;
278
279 retval = krb5_net_write(local_socket, (char *) &msg_length + 2, 2);
280 if (retval < 0) {
281 fprintf(stderr, "passwd: krb5_net_write failure\n");
282 goto finish;
283 }
284 }
285
286 local_addr.addrtype = ADDRTYPE_INET;
287 local_addr.length = SIZEOF_INADDR ;
288 local_addr.contents = (krb5_octet *)&local_sin.sin_addr;
289
290 foreign_addr.addrtype = ADDRTYPE_INET;
291 foreign_addr.length = SIZEOF_INADDR ;
292 foreign_addr.contents = (krb5_octet *)&remote_sin.sin_addr;
293
294 /* compute checksum, using CRC-32 */
295 if (!(send_cksum.contents = (krb5_octet *)
296 malloc(krb5_checksum_size(CKSUMTYPE_CRC32)))) {
297 fprintf(stderr, "passwd: Insufficient Memory while Allocating Checksum\n");
298 goto finish;
299 }
300 cksum_alloc++;
301 /* choose some random stuff to compute checksum from */
302 if (retval = krb5_calculate_checksum(CKSUMTYPE_CRC32,
303 ADM_CPW_VERSION,
304 strlen(ADM_CPW_VERSION),
305 0,
306 0, /* if length is 0, crc-32 doesn't
307 use the seed */
308 &send_cksum)) {
309 fprintf(stderr, "Error while Computing Checksum: %s\n",
310 error_message(retval));
311 goto finish;
312 }
313
314 /* call Kerberos library routine to obtain an authenticator,
315 pass it over the socket to the server, and obtain mutual
316 authentication. */
317
318 if ((retval = krb5_sendauth((krb5_pointer) &local_socket,
319 ADM_CPW_VERSION,
320 my_creds.client,
321 my_creds.server,
322 AP_OPTS_MUTUAL_REQUIRED,
323 &send_cksum,
324 0,
325 cache,
326 &seqno,
327 0, /* don't need a subsession key */
328 &err_ret,
329 &rep_ret))) {
330 fprintf(stderr, "passwd: Error while performing sendauth: %s\n",
331 error_message(retval));
332 goto finish;
333 }
334
335 /* Get credentials : to use for safe and private messages */
336 if (retval = krb5_get_credentials(0, cache, &my_creds)){
337 fprintf(stderr, "passwd: Error Obtaining Credentials: %s\n",
338 error_message(retval));
339 goto finish;
340 }
341
342 /* Read back what the server has to say... */
343 if (retval = krb5_read_message(&local_socket, &inbuf)){
344 fprintf(stderr, "passwd: Read Message Error: %s\n",
345 error_message(retval));
346 goto finish;
347 }
348 if ((inbuf.length != 2) || (inbuf.data[0] != KADMIND) ||
349 (inbuf.data[1] != KADMSAG)){
350 fprintf(stderr, "passwd: Invalid ack from admin server.\n");
351 goto finish;
352 }
353
354 inbuf.data[0] = KPASSWD;
355 inbuf.data[1] = CHGOPER;
356 inbuf.length = 2;
357
358 if ((retval = krb5_mk_priv(&inbuf,
359 ETYPE_DES_CBC_CRC,
360 &my_creds.keyblock,
361 &local_addr,
362 &foreign_addr,
363 seqno,
364 KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
365 0,
366 0,
367 &msg_data))) {
368 fprintf(stderr, "passwd: Error during First Message Encoding: %s\n",
369 error_message(retval));
370 goto finish;
371 }
372 free(inbuf.data);
373
374 /* write private message to server */
375 if (krb5_write_message(&local_socket, &msg_data)){
376 fprintf(stderr, "passwd: Write Error During First Message Transmission\n");
377 retval = 1;
378 goto finish;
379 }
380 free(msg_data.data);
381
382 (void)signal(SIGHUP, finish);
383 (void)signal(SIGINT, finish);
384
385 #ifdef MACH_PASS /* Machine-generated Passwords */
386 /* Ok Now let's get the private message */
387 if (retval = krb5_read_message(&local_socket, &inbuf)){
388 fprintf(stderr, "passwd: Read Error During First Reply: %s\n",
389 error_message(retval));
390 retval = 1;
391 goto finish;
392 }
393
394 if ((retval = krb5_rd_priv(&inbuf,
395 &my_creds.keyblock,
396 &foreign_addr,
397 &local_addr,
398 rep_ret->seq_number,
399 KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
400 0,
401 0,
402 &msg_data))) {
403 fprintf(stderr, "passwd: Error during First Read Decoding: %s\n",
404 error_message(retval));
405 goto finish;
406 }
407 free(inbuf.data);
408 #endif
409
410 if ((new_password = (char *) calloc (1, ADM_MAX_PW_LENGTH+1)) == NULL) {
411 fprintf(stderr, "passwd: Unable to Allocate Space for New Password\n");
412 goto finish;
413 }
414
415 #ifdef MACH_PASS /* Machine-generated passwords */
416 /* Offer Client Password Choices */
417 if ((retval = print_and_choose_password(new_password,
418 &msg_data))) {
419 (void) memset((char *) new_password, 0, ADM_MAX_PW_LENGTH+1);
420 free(new_password);
421 goto finish;
422 }
423 #else
424 new_pwsize = ADM_MAX_PW_LENGTH+1;
425 if ((retval = krb5_read_password("New Kerberos password: ",
426 "Retype new Kerberos password: ",
427 new_password,
428 &new_pwsize))) {
429 fprintf(stderr, "\nError while reading new password for '%s'\n",
430 client_name);
431 (void) memset((char *) new_password, 0, ADM_MAX_PW_LENGTH+1);
432 free(new_password);
433 goto finish;
434 }
435 #endif
436
437 inbuf.data = new_password;
438 inbuf.length = strlen(new_password);
439
440 if ((retval = krb5_mk_priv(&inbuf,
441 ETYPE_DES_CBC_CRC,
442 &my_creds.keyblock,
443 &local_addr,
444 &foreign_addr,
445 seqno,
446 KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
447 0,
448 0,
449 &msg_data))) {
450 fprintf(stderr, "passwd: Error during Second Message Encoding: %s\n",
451 error_message(retval));
452 goto finish;
453 }
454 memset(inbuf.data,0,inbuf.length);
455 free(inbuf.data);
456
457 /* write private message to server */
458 if (krb5_write_message(&local_socket, &msg_data)){
459 fprintf(stderr, "passwd: Write Error During Second Message Transmission\n");
460 retval = 1;
461 goto finish;
462 }
463 free(msg_data.data);
464
465 /* Ok Now let's get the private message */
466 if (retval = krb5_read_message(&local_socket, &inbuf)){
467 fprintf(stderr, "passwd: Read Error During Second Reply: %s\n",
468 error_message(retval));
469 retval = 1;
470 goto finish;
471 }
472
473 if ((retval = krb5_rd_priv(&inbuf,
474 &my_creds.keyblock,
475 &foreign_addr,
476 &local_addr,
477 rep_ret->seq_number,
478 KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
479 0,
480 0,
481 &msg_data))) {
482 fprintf(stderr, "passwd: Error during Second Read Decoding :%s\n",
483 error_message(retval));
484 goto finish;
485 }
486
487 rd_priv_resp.appl_code = msg_data.data[0];
488 rd_priv_resp.oper_code = msg_data.data[1];
489 rd_priv_resp.retn_code = msg_data.data[2];
490 if (msg_data.length > 3 && msg_data.data[3]) {
491 rd_priv_resp.message = malloc(msg_data.length - 2);
492 if (rd_priv_resp.message) {
493 memcpy(rd_priv_resp.message, msg_data.data + 3,
494 msg_data.length - 3);
495 rd_priv_resp.message[msg_data.length - 3] = 0;
496 }
497 } else
498 rd_priv_resp.message = NULL;
499
500
501 free(inbuf.data);
502 free(msg_data.data);
503 if (rd_priv_resp.appl_code == KPASSWD) {
504 if (rd_priv_resp.retn_code == KPASSBAD) {
505 if (rd_priv_resp.message)
506 fprintf(stderr, "passwd: %s\n", rd_priv_resp.message);
507 else
508 fprintf(stderr, "passwd: Server returned KPASSBAD.\n");
509 } else if (rd_priv_resp.retn_code != KPASSGOOD)
510 fprintf(stderr, "passwd: Server returned unknown kerberos code.\n");
511 } else
512 fprintf(stderr, "passwd: Server returned bad application code %d\n",
513 rd_priv_resp.appl_code);
514
515 if (rd_priv_resp.message)
516 free(rd_priv_resp.message);
517
518 finish:
519 (void) krb5_cc_destroy(cache);
520
521 free(client_name);
522 free(requested_realm.data);
523 if (cksum_alloc) free(send_cksum.contents);
524 if (retval) {
525 fprintf(stderr, "passwd: Protocol Failure - Password NOT changed\n");
526 exit(1);
527 }
528
529 exit(0);
530 }
531
532
533
534 krb5_data cpwname = {
535 sizeof(CPWNAME)-1,
536 CPWNAME
537 };
538
539 static krb5_error_code
540 get_first_ticket(cache, client)
541 krb5_ccache cache;
542 krb5_principal client;
543 {
544 char prompt[255]; /* for the password prompt */
545 char verify_prompt[255]; /* Verification Prompt if Desired */
546 char pword[ADM_MAX_PW_LENGTH+1]; /* storage for the password */
547 int pword_length = sizeof(pword);
548 char *old_password;
549 int old_pwsize;
550 int i;
551
552 krb5_address **my_addresses;
553
554 char *client_name;
555 char local_realm[255];
556 krb5_error_code retval;
557
558 if ((retval = krb5_unparse_name(client, &client_name))) {
559 fprintf(stderr, "Unable to Unparse Client Name\n");
560 return(1);
561 }
562
563 (void) printf("Changing Kerberos password for %s\n", client_name);
564
565 if ((retval = krb5_os_localaddr(&my_addresses))) {
566 fprintf(stderr, "passwd: Unable to Get Customers Address\n");
567 return(1);
568 }
569
570 memset((char *) &my_creds, 0, sizeof(my_creds));
571
572 my_creds.client = client;
573
574 if ((retval = krb5_build_principal_ext(&my_creds.server,
575 client->realm.length,
576 client->realm.data,
577 cpwname.length, /* 6 */
578 cpwname.data, /* "kadmin" */
579 client->realm.length,
580 /* instance is local realm */
581 client->realm.data,
582 0))) {
583 fprintf(stderr, "Error %s while building server name\n");
584 return(1);
585 }
586
587
588 if ((old_password = (char *) calloc (1, 255)) == NULL) {
589 fprintf(stderr, "passwd: No Memory for Retrieving old password\n");
590 return(1);
591 }
592
593 old_pwsize = 255;
594 if ((retval = krb5_read_password("Old kerberos password: ",
595 0,
596 old_password,
597 &old_pwsize))) {
598 fprintf(stderr, "\nError while reading password for '%s'\n",
599 client_name);
600 return(1);
601 }
602
603 /* Build Request for Initial Credentials */
604 for (i=0; preauth_search_list[i] >= 0; i++) {
605 retval = krb5_get_in_tkt_with_password(
606 0, /* options */
607 my_addresses,
608 /* do random preauth */
609 preauth_search_list[i],
610 ETYPE_DES_CBC_CRC, /* etype */
611 KEYTYPE_DES,
612 old_password,
613 cache,
614 &my_creds,
615 0);
616 if (retval != KRB5KDC_PREAUTH_FAILED &&
617 retval != KRB5KRB_ERR_GENERIC)
618 break;
619 }
620
621 if (retval) {
622 fprintf(stderr, "passwd: Unable to Get Initial Credentials : %s\n",
623 error_message(retval));
624 }
625
626 /* Do NOT Forget to zap password */
627 memset((char *) old_password, 0, old_pwsize);
628 free(old_password);
629 memset((char *) pword, 0, sizeof(pword));
630 return(retval);
631 }
632
633 #ifdef MACH_PASS /* Machine-generated Passwords */
634 static krb5_error_code
635 print_and_choose_password(new_password, decodable_pwd_string)
636 char * new_password;
637 krb5_data *decodable_pwd_string;
638 {
639 krb5_error_code retval;
640 krb5_pwd_data *pwd_data;
641 passwd_phrase_element **next_passwd_phrase_element;
642 char prompt[255];
643 char *verify_prompt = 0;
644 int i, j, k;
645 int legit_pswd = 0; /* Assume No Legitimate Password */
646 char *password_list[ADM_MAX_PW_CHOICES];
647 char verification_passwd[ADM_MAX_PW_LENGTH+1];
648 char phrase_in[ADM_MAX_PHRASE_LENGTH];
649 int new_passwd_length;
650 char *ptr;
651 int verify = 0; /* Do Not Request Password Selection Verification */
652 int ok = 0;
653
654 #define free_local_password_list() \
655 { for ( k = 0; k < i && k < ADM_MAX_PW_CHOICES; k++) { \
656 (void) memset(password_list[k], 0, ADM_MAX_PW_LENGTH); \
657 free(password_list[k]); } \
658 }
659
660 /* Decode Password and Phrase Information Obtained from krb5_rd_priv */
661 if ((retval = decode_krb5_pwd_data(decodable_pwd_string , &pwd_data))) {
662 fprintf(stderr, "passwd: Unable to Decode Passwords and Phrases\n");
663 fprintf(stderr, " Notify your System Administrator or the Kerberos Administrator\n");
664 return(1);
665 }
666
667 next_passwd_phrase_element = pwd_data->element;
668 /* Display List in 5 Password/Phrase Increments up to MAX Iterations */
669 memset((char *) phrase_in, 0, ADM_MAX_PHRASE_LENGTH);
670 for ( j = 0; j <= ADM_MAX_PW_ITERATIONS; j++) {
671 if (j == ADM_MAX_PW_ITERATIONS) {
672 fprintf(stderr, "passwd: Sorry - You Have Exceeded the List of Choices (%d) Allowed for Password\n",
673 ADM_MAX_PW_ITERATIONS * ADM_MAX_PW_CHOICES);
674 fprintf(stderr, " Modification. You Must Repeat this Operation in order to Successfully\n");
675 fprintf(stderr, " Change your Password.\n");
676 break;
677 }
678
679 display_print:
680 printf("Choose a password from the following list:\n");
681
682 printf("\nPassword Remembrance Aid\n");
683
684 /* Print Passwords and Assistance Phrases List */
685 for ( i = 0; i < ADM_MAX_PW_CHOICES; i++){
686 if ((password_list[i] = (char *) calloc (1,
687 ADM_MAX_PW_LENGTH + 1)) == NULL) {
688 fprintf(stderr, "passwd: Unable to Allocate Password List.\n");
689 return(1);
690 }
691
692 memcpy(password_list[i],
693 (*next_passwd_phrase_element)->passwd->data,
694 (*next_passwd_phrase_element)->passwd->length);
695 printf("%s ", password_list[i]);
696
697 memcpy((char *) phrase_in,
698 (*next_passwd_phrase_element)->phrase->data,
699 (*next_passwd_phrase_element)->phrase->length);
700 for ( k = 0;
701 k < 50 && k < (*next_passwd_phrase_element)->phrase->length;
702 k++) {
703 printf("%c", phrase_in[k]);
704 }
705 for ( k = k;
706 k < 70 && k < (*next_passwd_phrase_element)->phrase->length;
707 k++) {
708 if (phrase_in[k] == ' ') {
709 printf("\n ");
710 k++;
711 break;
712 } else {
713 printf("%c", phrase_in[k]);
714 }
715 }
716 for ( k = k;
717 k < (*next_passwd_phrase_element)->phrase->length;
718 k++) {
719 printf("%c", phrase_in[k]);
720 }
721 printf("\n");
722 memset((char *) phrase_in, 0, ADM_MAX_PHRASE_LENGTH);
723 next_passwd_phrase_element++;
724 }
725
726 sprintf(prompt,
727 "\nEnter Password Selection or a <CR> to get new list: ");
728
729 new_passwd_length = ADM_MAX_PW_LENGTH+1;
730 /* Read New Password from Terminal (Do Not Print on Screen) */
731 if ((retval = krb5_read_password(&prompt[0], 0,
732 new_password, &new_passwd_length))) {
733 fprintf(stderr,
734 "passwd: Error Reading Password Input or Input Aborted\n");
735 free_local_password_list();
736 break;;
737 }
738
739 /* Check for <CR> ==> Provide a New List */
740 if (new_passwd_length == 0) continue;
741
742 /* Check that Selection is from List - Server also does this */
743 legit_pswd = 0;
744 for (i = 0; i < ADM_MAX_PW_CHOICES && !legit_pswd; i++)
745 if ((retval = memcmp(new_password,
746 password_list[i], 8)) == 0) {
747 legit_pswd++;
748 }
749 free_local_password_list();
750
751 if (!(legit_pswd)) {
752 printf("\07\07Password must be from the specified list ");
753 printf("- Try Again\n");
754 }
755
756 if (legit_pswd) break; /* Exit Loop */
757 } /* ADM_MAX_PW_CHOICES Loop */
758
759 if (!(legit_pswd)) return (1);
760
761 return(0); /* SUCCESS */
762 }
763 #endif
764
765 static krb5_error_code
766 adm5_init_link(realm_of_server, local_socket)
767 krb5_data *realm_of_server;
768 int * local_socket;
769 {
770 struct servent *service_process; /* service we will talk to */
771 struct hostent *local_host; /* us */
772 struct hostent *remote_host; /* host we will talk to */
773 struct sockaddr *sockaddr_list;
774
775 char **hostlist;
776
777 int host_count;
778 int namelen;
779 int i, count;
780
781 krb5_error_code retval;
782
783 /* clear out the structure first */
784 (void) memset((char *)&remote_sin, 0, sizeof(remote_sin));
785
786 if ((service_process = getservbyname(CPW_SNAME, "tcp")) == NULL) {
787 fprintf(stderr, "passwd: Unable to find Service (%s) Check services file\n",
788 CPW_SNAME);
789 return(1);
790 }
791
792 /* Copy the Port Number */
793 remote_sin.sin_port = service_process->s_port;
794
795 hostlist = 0;
796
797 /* Identify all Hosts Associated with this Realm */
798 if ((retval = krb5_get_krbhst (realm_of_server, &hostlist))) {
799 fprintf(stderr, "passwd: Unable to Determine Server Name\n");
800 return(1);
801 }
802
803 for (i=0; hostlist[i]; i++);
804
805 count = i;
806
807 if (count == 0) {
808 host_count = 0;
809 fprintf(stderr, "passwd: No hosts found\n");
810 return(1);
811 }
812
813 for (i=0; hostlist[i]; i++) {
814 remote_host = gethostbyname(hostlist[i]);
815 if (remote_host != 0) {
816
817 /* set up the address of the foreign socket for connect() */
818 remote_sin.sin_family = remote_host->h_addrtype;
819 (void) memcpy((char *) &remote_sin.sin_addr,
820 (char *) remote_host->h_addr,
821 sizeof(remote_host->h_addr));
822 break; /* Only Need one */
823 }
824 }
825
826 free ((char *)hostlist);
827
828 /* open a TCP socket */
829 *local_socket = socket(PF_INET, SOCK_STREAM, 0);
830 if (*local_socket < 0) {
831 fprintf(stderr, "passwd: Cannot Open Socket\n");
832 return(1);
833 }
834 /* connect to the server */
835 if (connect(*local_socket, (struct sockaddr *)&remote_sin, sizeof(remote_sin)) < 0) {
836 fprintf(stderr, "passwd: Cannot Connect to Socket\n");
837 close(*local_socket);
838 return(1);
839 }
840
841 /* find out who I am, now that we are connected and therefore bound */
842 namelen = sizeof(local_sin);
843 if (getsockname(*local_socket,
844 (struct sockaddr *) &local_sin, &namelen) < 0) {
845 fprintf(stderr, "passwd: Cannot Perform getsockname\n");
846 close(*local_socket);
847 return(1);
848 }
849 return(0);
850 }
851
852 static void
853 finish()
854 {
855 exit(1);
856 }
857
858 #ifdef KRB_NONETWORK
859 #include <utmp.h>
860
861 #ifndef MAXHOSTNAME
862 #define MAXHOSTNAME 64
863 #endif
864
865 int utfile; /* Global utfile file descriptor for BSD version
866 of setutent, getutline, and endutent */
867
868 #if !defined(SYSV) && !defined(UMIPS) /* Setutent, Endutent, and getutline
869 routines for non System V Unix
870 systems */
871 #include <fcntl.h>
872
873 void setutent()
874 {
875 utfile = open("/etc/utmp",O_RDONLY);
876 }
877
878 struct utmp * getutline(utmpent)
879 struct utmp *utmpent;
880 {
881 static struct utmp tmputmpent;
882 int found = 0;
883 while ( read(utfile,&tmputmpent,sizeof(struct utmp)) > 0 ){
884 if ( strcmp(tmputmpent.ut_line,utmpent->ut_line) == 0){
885 #ifdef NO_UT_HOST
886 if ( ( 1) &&
887 #else
888 if ( (strcmp(tmputmpent.ut_host,"") == 0) &&
889 #endif
890 (strcmp(tmputmpent.ut_name,"") == 0)) continue;
891 found = 1;
892 break;
893 }
894 }
895 if (found)
896 return(&tmputmpent);
897 return((struct utmp *) 0);
898 }
899
900 void endutent()
901 {
902 close(utfile);
903 }
904 #endif /* not SYSV */
905
906
907 int network_connected()
908 {
909 struct utmp utmpent;
910 struct utmp retutent, *tmpptr;
911 char *display_indx;
912 char currenthost[MAXHOSTNAME];
913 char *username,*tmpname;
914
915
916 /* Macro for pseudo_tty */
917 #define pseudo_tty(ut) \
918 ((strncmp((ut).ut_line, "tty", 3) == 0 && ((ut).ut_line[3] == 'p' \
919 || (ut).ut_line[3] == 'q' \
920 || (ut).ut_line[3] == 'r' \
921 || (ut).ut_line[3] == 's'))\
922 || (strncmp((ut).ut_line, "pty", 3) == 0))
923
924 /* Check to see if getlogin returns proper name */
925 if ( (tmpname = (char *) getlogin()) == (char *) 0) return(1);
926 username = (char *) malloc(strlen(tmpname) + 1);
927 if ( username == (char *) 0) return(1);
928 strcpy(username,tmpname);
929
930 /* Obtain tty device for controlling tty of current process.*/
931 strncpy(utmpent.ut_line,ttyname(0) + strlen("/dev/"),
932 sizeof(utmpent.ut_line));
933
934 /* See if this device is currently listed in /etc/utmp under
935 calling user */
936 #ifdef SYSV
937 utmpent.ut_type = USER_PROCESS;
938 #define ut_name ut_user
939 #endif
940 setutent();
941 while ( (tmpptr = (struct utmp *) getutline(&utmpent))
942 != ( struct utmp *) 0) {
943
944 /* If logged out name and host will be empty */
945 if ((strcmp(tmpptr->ut_name,"") == 0) &&
946 #ifdef NO_UT_HOST
947 ( 1)) continue;
948 #else
949 (strcmp(tmpptr->ut_host,"") == 0)) continue;
950 #endif
951 else break;
952 }
953 if ( tmpptr == (struct utmp *) 0) {
954 endutent();
955 return(1);
956 }
957 bcopy((char *)&retutent, (char *)tmpptr, sizeof(struct utmp));
958 endutent();
959 #ifdef DEBUG
960 #ifdef NO_UT_HOST
961 printf("User %s on line %s :\n",
962 retutent.ut_name,retutent.ut_line);
963 #else
964 printf("User %s on line %s connected from host :%s:\n",
965 retutent.ut_name,retutent.ut_line,retutent.ut_host);
966 #endif
967 #endif
968 if (strcmp(retutent.ut_name,username) != 0) {
969 return(1);
970 }
971
972
973 /* If this is not a pseudo tty then everything is OK */
974 if (! pseudo_tty(retutent)) return(0);
975
976 /* OK now the work begins there is an entry in utmp and
977 the device is a pseudo tty. */
978
979 /* Check if : is in hostname if so this is xwindow display */
980
981 if (gethostname(currenthost,sizeof(currenthost))) return(1);
982 #ifdef NO_UT_HOST
983 display_indx = (char *) 0;
984 #else
985 display_indx = (char *) strchr(retutent.ut_host,':');
986 #endif
987 if ( display_indx != (char *) 0) {
988 /*
989 We have X window application here. The host field should have
990 the form => local_system_name:0.0 or :0.0
991 if the window is being displayed on the local system.
992 */
993 #ifdef NO_UT_HOST
994 return(1);
995 #else
996 if (strncmp(currenthost,retutent.ut_host,
997 (display_indx - retutent.ut_host)) != 0) return(1);
998 else return(0);
999 #endif
1000 }
1001
1002 /* Host field is empty or is not X window entry. At this point
1003 we can't trust that the pseudo tty is not connected to a
1004 networked process so let's return 1.
1005 */
1006 return(1);
1007 }
1008
1009 int networked()
1010 {
1011 return(network_connected());
1012 }
1013 #endif
1014
1015 #endif /* KERBEROS5 */
1016