1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * user.c: support for the scadm useradd, userdel, usershow, userpassword,
29  * userperm options (administration of service processor users)
30  */
31 
32 #include <libintl.h>
33 #include <signal.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <termios.h>
37 #include <time.h>  /* required by librsc.h */
38 
39 #include "librsc.h"
40 #include "adm.h"
41 
42 
43 static void ADM_Get_Password(char  *password);
44 static void ADM_Destroy_Password(char  *password);
45 static void max_username();
46 static void malformed_username();
47 static void wrong_response();
48 static void no_user();
49 static void no_info();
50 static void userperm_usage();
51 static void show_header();
52 static void cleanup();
53 
54 
55 /* Globals so that exit routine can clean up echo */
56 static int		echoOff = 0;
57 static struct termios	oldOpts;
58 
59 typedef union {
60 	char	DataBuffer[DP_MAX_MSGLEN];
61 	void	*DataBuffer_p;
62 } data_buffer_t;
63 
64 
65 void
ADM_Process_useradd(int argc,char * argv[])66 ADM_Process_useradd(int argc, char *argv[])
67 {
68 	static data_buffer_t	dataBuffer;
69 	rscp_msg_t		Message;
70 	struct timespec		Timeout;
71 	dp_user_adm_t		*admMessage;
72 	dp_user_adm_r_t		*admResponse;
73 	char			*userName;
74 
75 
76 	if (argc != 3) {
77 		(void) fprintf(stderr, "\n%s\n\n",
78 		    gettext("USAGE: scadm useradd <username>"));
79 		exit(-1);
80 	}
81 
82 	ADM_Start();
83 
84 	if (strlen(argv[2]) > DP_USER_NAME_SIZE) {
85 		max_username();
86 		exit(-1);
87 	}
88 
89 	admMessage = (dp_user_adm_t *)&dataBuffer;
90 	userName   = (char *)(&((char *)admMessage)[sizeof (dp_user_adm_t)]);
91 	admMessage->command = DP_USER_CMD_ADD;
92 	(void) strcpy(userName, argv[2]);
93 
94 	Message.type = DP_USER_ADM;
95 	Message.len  = sizeof (dp_user_adm_t) + strlen(userName) + 1;
96 	Message.data = admMessage;
97 	ADM_Send(&Message);
98 
99 	Timeout.tv_nsec = 0;
100 	Timeout.tv_sec  = ADM_SEPROM_TIMEOUT;
101 	ADM_Recv(&Message, &Timeout, DP_USER_ADM_R, sizeof (dp_user_adm_r_t));
102 
103 	admResponse = (dp_user_adm_r_t *)Message.data;
104 	if (admResponse->command != DP_USER_CMD_ADD) {
105 		wrong_response();
106 		exit(-1);
107 	}
108 
109 	if (admResponse->status == DP_ERR_USER_FULL) {
110 		(void) fprintf(stderr, "\n%s\n\n",
111 		    gettext("scadm: all user slots are full"));
112 		exit(-1);
113 	} else if (admResponse->status == DP_ERR_USER_THERE) {
114 		(void) fprintf(stderr, "\n%s\n\n",
115 		    gettext("scadm: user already exists"));
116 		exit(-1);
117 	} else if (admResponse->status == DP_ERR_USER_WARNING) {
118 		(void) fprintf(stderr, "\n%s\n\n",
119 		    gettext("scadm: username did not start with letter\n"
120 		    "        or did not contain lower case letter\n"));
121 		exit(-1);
122 	} else if (admResponse->status == DP_ERR_USER_BAD) {
123 		malformed_username();
124 		exit(-1);
125 	} else if (admResponse->status != 0) {
126 		(void) fprintf(stderr, "\n%s\n\n",
127 		    gettext("scadm: couldn't add user"));
128 		exit(-1);
129 	}
130 
131 	ADM_Free(&Message);
132 }
133 
134 
135 void
ADM_Process_userdel(int argc,char * argv[])136 ADM_Process_userdel(int argc, char *argv[])
137 {
138 	static data_buffer_t	dataBuffer;
139 	rscp_msg_t		Message;
140 	struct timespec		Timeout;
141 	dp_user_adm_t		*admMessage;
142 	dp_user_adm_r_t		*admResponse;
143 	char			*userName;
144 
145 
146 	if (argc != 3) {
147 		(void) fprintf(stderr, "\n%s\n\n",
148 		    gettext("USAGE: scadm userdel <username>"));
149 		exit(-1);
150 	}
151 
152 	ADM_Start();
153 
154 	if (strlen(argv[2]) > DP_USER_NAME_SIZE) {
155 		max_username();
156 		exit(-1);
157 	}
158 
159 	admMessage = (dp_user_adm_t *)&dataBuffer;
160 	userName   = (char *)(&((char *)admMessage)[sizeof (dp_user_adm_t)]);
161 	admMessage->command = DP_USER_CMD_DEL;
162 	(void) strcpy(userName, argv[2]);
163 
164 	Message.type = DP_USER_ADM;
165 	Message.len  = sizeof (dp_user_adm_t) + strlen(userName) + 1;
166 	Message.data = admMessage;
167 	ADM_Send(&Message);
168 
169 	Timeout.tv_nsec = 0;
170 	Timeout.tv_sec  = ADM_SEPROM_TIMEOUT;
171 	ADM_Recv(&Message, &Timeout, DP_USER_ADM_R, sizeof (dp_user_adm_r_t));
172 
173 	admResponse = (dp_user_adm_r_t *)Message.data;
174 	if (admResponse->command != DP_USER_CMD_DEL) {
175 		wrong_response();
176 		exit(-1);
177 	}
178 
179 	if (admResponse->status == DP_ERR_USER_NONE) {
180 		no_user();
181 		exit(-1);
182 	} else if (admResponse->status == DP_ERR_USER_BAD) {
183 		malformed_username();
184 		exit(-1);
185 	} else if (admResponse->status != 0) {
186 		(void) fprintf(stderr, "\n%s\n\n",
187 		    gettext("scadm: couldn't delete user"));
188 		exit(-1);
189 	}
190 
191 	ADM_Free(&Message);
192 }
193 
194 
195 void
ADM_Process_usershow(int argc,char * argv[])196 ADM_Process_usershow(int argc, char *argv[])
197 {
198 	static data_buffer_t	dataBuffer;
199 	rscp_msg_t		Message;
200 	struct timespec		Timeout;
201 	dp_user_adm_t		*admMessage;
202 	dp_user_adm_r_t		*admResponse;
203 	char			*userName;
204 	char			*permissions;
205 	char			*passwd;
206 	int			index;
207 
208 
209 
210 	if ((argc != 2) && (argc != 3)) {
211 		(void) fprintf(stderr, "\n%s\n\n",
212 		    gettext("USAGE: scadm usershow [username]"));
213 		exit(-1);
214 	}
215 
216 	ADM_Start();
217 
218 	if (argc == 3) {
219 		admMessage = (dp_user_adm_t *)&dataBuffer;
220 		admMessage->command = DP_USER_CMD_SHOW;
221 		Message.type = DP_USER_ADM;
222 		Message.data = admMessage;
223 
224 		if (strlen(argv[2]) > DP_USER_NAME_SIZE) {
225 			max_username();
226 			exit(-1);
227 		}
228 		userName = (char *)(&((char *)admMessage)[
229 		    sizeof (dp_user_adm_t)]);
230 		(void) strcpy(userName, argv[2]);
231 		admMessage->parm = DP_USER_SHOW_USERNAME;
232 		Message.len = sizeof (dp_user_adm_t) + strlen(userName) + 1;
233 		ADM_Send(&Message);
234 
235 		Timeout.tv_nsec = 0;
236 		Timeout.tv_sec  = ADM_SEPROM_TIMEOUT;
237 		ADM_Recv(&Message, &Timeout,
238 		    DP_USER_ADM_R, sizeof (dp_user_adm_r_t));
239 
240 		admResponse = (dp_user_adm_r_t *)Message.data;
241 		if (admResponse->command != DP_USER_CMD_SHOW) {
242 			wrong_response();
243 			exit(-1);
244 		}
245 
246 		if (admResponse->status == DP_ERR_USER_NONE) {
247 			no_user();
248 			exit(-1);
249 		} else if (admResponse->status == DP_ERR_USER_BAD) {
250 			malformed_username();
251 			exit(-1);
252 		} else if (admResponse->status != 0) {
253 			no_info();
254 			exit(-1);
255 		}
256 
257 		userName = &(((char *)admResponse)[
258 		    sizeof (dp_user_adm_r_t)]);
259 		permissions = &userName[strlen(userName)+1];
260 		passwd = &permissions[strlen(permissions)+1];
261 		show_header();
262 		(void) printf(" %-16s    %-15s    ", userName, permissions);
263 		if (strncmp(passwd, "Assigned", 12) == 0) {
264 			(void) printf("%s\n\n", gettext("Assigned"));
265 		} else if (strncmp(passwd, "None", 12) == 0) {
266 			(void) printf("%s\n\n", gettext("None"));
267 		} else {
268 			(void) printf("%-12s\n\n", passwd);
269 		}
270 		ADM_Free(&Message);
271 	} else {
272 		show_header();
273 		for (index = 1; index <= DP_USER_MAX; index++) {
274 			admMessage = (dp_user_adm_t *)&dataBuffer;
275 			admMessage->command = DP_USER_CMD_SHOW;
276 			admMessage->parm    = index;
277 
278 			Message.type = DP_USER_ADM;
279 			Message.data = admMessage;
280 			Message.len  = sizeof (dp_user_adm_t);
281 			ADM_Send(&Message);
282 
283 			Timeout.tv_nsec = 0;
284 			Timeout.tv_sec  = ADM_SEPROM_TIMEOUT;
285 			ADM_Recv(&Message, &Timeout,
286 			    DP_USER_ADM_R, sizeof (dp_user_adm_r_t));
287 
288 			admResponse = (dp_user_adm_r_t *)Message.data;
289 			if (admResponse->command != DP_USER_CMD_SHOW) {
290 				wrong_response();
291 				exit(-1);
292 			}
293 
294 			if (admResponse->status == DP_ERR_USER_NONE) {
295 				ADM_Free(&Message);
296 				continue;
297 			} else if (admResponse->status == DP_ERR_USER_BAD) {
298 				malformed_username();
299 				exit(-1);
300 			} else if (admResponse->status != 0) {
301 				no_info();
302 				exit(-1);
303 			}
304 
305 			userName = &(((char *)admResponse)[
306 			    sizeof (dp_user_adm_r_t)]);
307 			permissions = &userName[strlen(userName)+1];
308 			passwd = &permissions[strlen(permissions)+1];
309 			(void) printf(" %-16s    %-15s    ",
310 			    userName, permissions);
311 			if (strncmp(passwd, "Assigned", 12) == 0) {
312 				(void) printf("%s\n", gettext("Assigned"));
313 			} else if (strncmp(passwd, "None", 12) == 0) {
314 				(void) printf("%s\n", gettext("None"));
315 			} else {
316 				(void) printf("%-12s\n", passwd);
317 			}
318 
319 			ADM_Free(&Message);
320 		}
321 		(void) printf("\n");
322 	}
323 }
324 
325 
326 void
ADM_Process_userpassword(int argc,char * argv[])327 ADM_Process_userpassword(int argc, char *argv[])
328 {
329 	static data_buffer_t	dataBuffer;
330 	rscp_msg_t		Message;
331 	struct timespec		Timeout;
332 	dp_user_adm_t		*admMessage;
333 	dp_user_adm_r_t		*admResponse;
334 	char			*userName;
335 	char			*password;
336 	int			passTry;
337 
338 
339 	/* Try to set password up to 3 times on Malformed password */
340 	passTry = 3;
341 
342 	if (argc != 3) {
343 		(void) fprintf(stderr, "\n%s\n\n",
344 		    gettext("USAGE: scadm userpassword <username>"));
345 		exit(-1);
346 	}
347 
348 	ADM_Start();
349 
350 	if (strlen(argv[2]) > DP_USER_NAME_SIZE) {
351 		max_username();
352 		exit(-1);
353 	}
354 
355 	admMessage = (dp_user_adm_t *)&dataBuffer;
356 	admMessage->command = DP_USER_CMD_PASSWORD;
357 	userName = (&((char *)admMessage)[sizeof (dp_user_adm_t)]);
358 	(void) strcpy(userName, argv[2]);
359 	password = (&((char *)admMessage)[sizeof (dp_user_adm_t) +
360 	    strlen(userName) + 1]);
361 
362 	for (;;) {
363 		ADM_Get_Password(password);
364 
365 		Message.type = DP_USER_ADM;
366 		Message.len  = sizeof (dp_user_adm_t) + strlen(userName) +
367 		    strlen(password) + 2;
368 		Message.data = admMessage;
369 		ADM_Send(&Message);
370 
371 		ADM_Destroy_Password(password);
372 		Timeout.tv_nsec = 0;
373 		Timeout.tv_sec  = ADM_SEPROM_TIMEOUT;
374 		ADM_Recv(&Message, &Timeout,
375 		    DP_USER_ADM_R, sizeof (dp_user_adm_r_t));
376 
377 		admResponse = (dp_user_adm_r_t *)Message.data;
378 		if (admResponse->command != DP_USER_CMD_PASSWORD) {
379 			wrong_response();
380 			exit(-1);
381 		}
382 
383 		if (admResponse->status == DP_ERR_USER_NONE) {
384 			no_user();
385 			exit(-1);
386 		} else if (admResponse->status == DP_ERR_USER_BAD) {
387 			malformed_username();
388 			exit(-1);
389 		} else if (admResponse->status == DP_ERR_USER_PASSWD) {
390 			(void) fprintf(stderr, "\n%s\n\n",
391 			    gettext("scadm: malformed password\n"
392 			    "        A valid password is between 6 and 8 "
393 			    "characters,\n"
394 			    "        has at least two alphabetic characters, "
395 			    "and at\n"
396 			    "        least one numeric or special character. "
397 			    "The\n"
398 			    "        password must differ from the user's "
399 			    "login name\n"
400 			    "        and any reverse or circular shift of that "
401 			    "login\n"
402 			    "        name.\n"));
403 			passTry--;
404 			if (passTry > 0) {
405 				ADM_Free(&Message);
406 				continue;
407 			} else
408 				exit(-1);
409 		} else if (admResponse->status != 0) {
410 			(void) fprintf(stderr, "\n%s\n\n",
411 			    gettext("scadm: couldn't change password"));
412 			exit(-1);
413 		}
414 
415 		/* password was changed successfully, get out of while */
416 		break;
417 	}
418 
419 	ADM_Free(&Message);
420 }
421 
422 
423 void
ADM_Process_userperm(int argc,char * argv[])424 ADM_Process_userperm(int argc, char *argv[])
425 {
426 	static data_buffer_t	dataBuffer;
427 	rscp_msg_t		Message;
428 	struct timespec		Timeout;
429 	dp_user_adm_t		*admMessage;
430 	dp_user_adm_r_t		*admResponse;
431 	char			*userName;
432 	int			permissions;
433 	int			index;
434 
435 
436 	if ((argc != 3) && (argc != 4)) {
437 		userperm_usage();
438 		exit(-1);
439 	}
440 
441 	if (argc == 3) {
442 		permissions = 0;
443 	} else {
444 		if ((strlen(argv[3]) > 4) || (strlen(argv[3]) < 1)) {
445 			userperm_usage();
446 			exit(-1);
447 		}
448 
449 		permissions = 0;
450 		for (index = 0; index < strlen(argv[3]); index++) {
451 			if ((argv[3][index] != 'c') &&
452 			    (argv[3][index] != 'C') &&
453 			    (argv[3][index] != 'u') &&
454 			    (argv[3][index] != 'U') &&
455 			    (argv[3][index] != 'a') &&
456 			    (argv[3][index] != 'A') &&
457 			    (argv[3][index] != 'r') &&
458 			    (argv[3][index] != 'R')) {
459 				userperm_usage();
460 				exit(-1);
461 			}
462 
463 			if ((argv[3][index] == 'c') ||
464 			    (argv[3][index] == 'C')) {
465 				/* See if this field was entered twice */
466 				if ((permissions & DP_USER_PERM_C) != 0) {
467 					userperm_usage();
468 					exit(-1);
469 				}
470 				permissions = permissions | DP_USER_PERM_C;
471 			}
472 
473 			if ((argv[3][index] == 'u') ||
474 			    (argv[3][index] == 'U')) {
475 				/* See if this field was enetered twice */
476 				if ((permissions & DP_USER_PERM_U) != 0) {
477 					userperm_usage();
478 					exit(-1);
479 				}
480 				permissions = permissions | DP_USER_PERM_U;
481 			}
482 
483 			if ((argv[3][index] == 'a') ||
484 			    (argv[3][index] == 'A')) {
485 				/* See if this field was enetered twice */
486 				if ((permissions & DP_USER_PERM_A) != 0) {
487 					userperm_usage();
488 					exit(-1);
489 				}
490 				permissions = permissions | DP_USER_PERM_A;
491 			}
492 
493 			if ((argv[3][index] == 'r') ||
494 			    (argv[3][index] == 'R')) {
495 				/* See if this field was enetered twice */
496 				if ((permissions & DP_USER_PERM_R) != 0) {
497 					userperm_usage();
498 					exit(-1);
499 				}
500 				permissions = permissions | DP_USER_PERM_R;
501 			}
502 		}
503 	}
504 
505 	ADM_Start();
506 
507 	if (strlen(argv[2]) > DP_USER_NAME_SIZE) {
508 		max_username();
509 		exit(-1);
510 	}
511 
512 	admMessage = (dp_user_adm_t *)&dataBuffer;
513 	admMessage->command = DP_USER_CMD_PERM;
514 	admMessage->parm    = permissions;
515 	userName   = (char *)(&((char *)admMessage)[sizeof (dp_user_adm_t)]);
516 	(void) strcpy(userName, argv[2]);
517 
518 	Message.type = DP_USER_ADM;
519 	Message.len  = sizeof (dp_user_adm_t) + strlen(userName) + 1;
520 	Message.data = admMessage;
521 	ADM_Send(&Message);
522 
523 	Timeout.tv_nsec = 0;
524 	Timeout.tv_sec  = ADM_SEPROM_TIMEOUT;
525 	ADM_Recv(&Message, &Timeout, DP_USER_ADM_R, sizeof (dp_user_adm_r_t));
526 
527 	admResponse = (dp_user_adm_r_t *)Message.data;
528 	if (admResponse->command != DP_USER_CMD_PERM) {
529 		wrong_response();
530 		exit(-1);
531 	}
532 
533 	if (admResponse->status == DP_ERR_USER_NONE) {
534 		no_user();
535 		exit(-1);
536 	} else if (admResponse->status == DP_ERR_USER_BAD) {
537 		malformed_username();
538 		exit(-1);
539 	} else if (admResponse->status != 0) {
540 		(void) fprintf(stderr, "\n%s\n\n",
541 		    gettext("scadm: couldn't change permissions"));
542 		exit(-1);
543 	}
544 
545 	ADM_Free(&Message);
546 }
547 
548 
549 static void
ADM_Get_Password(char * password)550 ADM_Get_Password(char *password)
551 {
552 	static char		pass1[64];
553 	static char		pass2[64];
554 	static struct termios	newOpts;
555 	int			passTry;
556 	int			validPass;
557 
558 
559 	validPass = 0;
560 	passTry   = 3;
561 
562 	if (signal(SIGINT, cleanup) == SIG_ERR) {
563 		(void) fprintf(stderr, "\n%s\n\n",
564 		    gettext("scadm: cleanup() registration failed"));
565 		exit(-1);
566 	}
567 
568 	echoOff = 1;
569 	(void) tcgetattr(0, &oldOpts);
570 	newOpts = oldOpts;
571 	newOpts.c_lflag &= ~ECHO;
572 	(void) tcsetattr(0, TCSANOW, &newOpts);
573 
574 	while ((passTry > 0) && (validPass == 0)) {
575 		passTry = passTry - 1;
576 		(void) printf("%s", gettext("Password: "));
577 		(void) scanf("%s", pass1);
578 		(void) printf("\n");
579 		(void) fflush(stdin);
580 		(void) printf("%s", gettext("Re-enter Password: "));
581 		(void) scanf("%s", pass2);
582 		(void) printf("\n");
583 
584 		/* Truncate at 8 characters  */
585 		pass1[8] = pass2[8] = '\0';
586 
587 		if ((strcmp(pass1, pass2) != 0) && (passTry > 0)) {
588 			ADM_Destroy_Password(pass1);
589 			ADM_Destroy_Password(pass2);
590 			(void) fprintf(stderr, "%s\n\n",
591 			    gettext("Passwords didn't match, try again"));
592 		} else if ((strcmp(pass1, pass2) != 0) && (passTry <= 0)) {
593 			ADM_Destroy_Password(pass1);
594 			ADM_Destroy_Password(pass2);
595 			(void) fprintf(stderr, "\n%s\n\n",
596 			    gettext("scadm: ERROR, passwords didn't match"));
597 			(void) tcsetattr(0, TCSANOW, &oldOpts);
598 			exit(-1);
599 		} else {
600 			validPass = 1;
601 		}
602 	}
603 
604 	(void) tcsetattr(0, TCSANOW, &oldOpts);
605 	echoOff = 0;
606 	(void) strcpy(password, pass1);
607 	ADM_Destroy_Password(pass1);
608 	ADM_Destroy_Password(pass2);
609 }
610 
611 
612 static void
cleanup()613 cleanup()
614 {
615 	if (echoOff)
616 		(void) tcsetattr(0, TCSANOW, &oldOpts);
617 
618 	exit(-1);
619 }
620 
621 
622 static void
ADM_Destroy_Password(char * password)623 ADM_Destroy_Password(char *password)
624 {
625 	int index;
626 
627 	for (index = 0; index < strlen(password); index++)
628 		password[index] = 0x1;
629 }
630 
631 
632 static void
max_username()633 max_username()
634 {
635 	(void) fprintf(stderr,
636 	    gettext("\nscadm: maximum username length is %d\n\n"),
637 	    DP_USER_NAME_SIZE);
638 }
639 
640 
641 static void
malformed_username()642 malformed_username()
643 {
644 	(void) fprintf(stderr,
645 	    "\n%s\n\n", gettext("scadm: malformed username"));
646 }
647 
648 
649 static void
wrong_response()650 wrong_response()
651 {
652 	(void) fprintf(stderr, "\n%s\n\n",
653 	    gettext("scadm: SC returned wrong response"));
654 }
655 
656 
657 static void
no_user()658 no_user()
659 {
660 	(void) fprintf(stderr,
661 	    "\n%s\n\n", gettext("scadm: username does not exist"));
662 }
663 
664 
665 static void
no_info()666 no_info()
667 {
668 	(void) fprintf(stderr, "\n%s\n\n",
669 	    gettext("scadm: couldn't get information on user"));
670 }
671 
672 
673 static void
userperm_usage()674 userperm_usage()
675 {
676 	(void) fprintf(stderr, "\n%s\n\n",
677 	    gettext("USAGE: scadm userperm <username> [cuar]"));
678 }
679 
680 
681 static void
show_header()682 show_header()
683 {
684 	int i;
685 	int usernLen = strlen(gettext("username"));
686 	int permLen = strlen(gettext("permissions"));
687 	int pwdLen = strlen(gettext("password"));
688 
689 	(void) printf("\n");
690 	(void) putchar(' ');
691 	(void) printf("%s", gettext("username"));
692 	for (i = 0; i < (20 - usernLen); i++)
693 		(void) putchar(' ');
694 
695 	(void) printf("%s", gettext("permissions"));
696 	for (i = 0; i < (19 - permLen); i++)
697 		(void) putchar(' ');
698 
699 	(void) printf("%s\n", gettext("password"));
700 
701 	(void) putchar(' ');
702 	for (i = 0; i < usernLen; i++)
703 		(void) putchar('-');
704 	for (; i < 20; i++)
705 		(void) putchar(' ');
706 
707 	for (i = 0; i < permLen; i++)
708 		(void) putchar('-');
709 	for (; i < 19; i++)
710 		(void) putchar(' ');
711 
712 	for (i = 0; i < pwdLen; i++)
713 		(void) putchar('-');
714 	(void) printf("\n");
715 }
716