root/usr/src/cmd/scadm/sparc/mpxu/common/user.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * user.c: support for the scadm useradd, userdel, usershow, userpassword,
 * userperm options (administration of service processor users)
 */

#include <libintl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <time.h>  /* required by librsc.h */

#include "librsc.h"
#include "adm.h"


static void ADM_Get_Password(char  *password);
static void ADM_Destroy_Password(char  *password);
static void max_username();
static void malformed_username();
static void wrong_response();
static void no_user();
static void no_info();
static void userperm_usage();
static void show_header();
static void cleanup();


/* Globals so that exit routine can clean up echo */
static int              echoOff = 0;
static struct termios   oldOpts;

typedef union {
        char    DataBuffer[DP_MAX_MSGLEN];
        void    *DataBuffer_p;
} data_buffer_t;


void
ADM_Process_useradd(int argc, char *argv[])
{
        static data_buffer_t    dataBuffer;
        rscp_msg_t              Message;
        struct timespec         Timeout;
        dp_user_adm_t           *admMessage;
        dp_user_adm_r_t         *admResponse;
        char                    *userName;


        if (argc != 3) {
                (void) fprintf(stderr, "\n%s\n\n",
                    gettext("USAGE: scadm useradd <username>"));
                exit(-1);
        }

        ADM_Start();

        if (strlen(argv[2]) > DP_USER_NAME_SIZE) {
                max_username();
                exit(-1);
        }

        admMessage = (dp_user_adm_t *)&dataBuffer;
        userName   = (char *)(&((char *)admMessage)[sizeof (dp_user_adm_t)]);
        admMessage->command = DP_USER_CMD_ADD;
        (void) strcpy(userName, argv[2]);

        Message.type = DP_USER_ADM;
        Message.len  = sizeof (dp_user_adm_t) + strlen(userName) + 1;
        Message.data = admMessage;
        ADM_Send(&Message);

        Timeout.tv_nsec = 0;
        Timeout.tv_sec  = ADM_SEPROM_TIMEOUT;
        ADM_Recv(&Message, &Timeout, DP_USER_ADM_R, sizeof (dp_user_adm_r_t));

        admResponse = (dp_user_adm_r_t *)Message.data;
        if (admResponse->command != DP_USER_CMD_ADD) {
                wrong_response();
                exit(-1);
        }

        if (admResponse->status == DP_ERR_USER_FULL) {
                (void) fprintf(stderr, "\n%s\n\n",
                    gettext("scadm: all user slots are full"));
                exit(-1);
        } else if (admResponse->status == DP_ERR_USER_THERE) {
                (void) fprintf(stderr, "\n%s\n\n",
                    gettext("scadm: user already exists"));
                exit(-1);
        } else if (admResponse->status == DP_ERR_USER_WARNING) {
                (void) fprintf(stderr, "\n%s\n\n",
                    gettext("scadm: username did not start with letter\n"
                    "        or did not contain lower case letter\n"));
                exit(-1);
        } else if (admResponse->status == DP_ERR_USER_BAD) {
                malformed_username();
                exit(-1);
        } else if (admResponse->status != 0) {
                (void) fprintf(stderr, "\n%s\n\n",
                    gettext("scadm: couldn't add user"));
                exit(-1);
        }

        ADM_Free(&Message);
}


void
ADM_Process_userdel(int argc, char *argv[])
{
        static data_buffer_t    dataBuffer;
        rscp_msg_t              Message;
        struct timespec         Timeout;
        dp_user_adm_t           *admMessage;
        dp_user_adm_r_t         *admResponse;
        char                    *userName;


        if (argc != 3) {
                (void) fprintf(stderr, "\n%s\n\n",
                    gettext("USAGE: scadm userdel <username>"));
                exit(-1);
        }

        ADM_Start();

        if (strlen(argv[2]) > DP_USER_NAME_SIZE) {
                max_username();
                exit(-1);
        }

        admMessage = (dp_user_adm_t *)&dataBuffer;
        userName   = (char *)(&((char *)admMessage)[sizeof (dp_user_adm_t)]);
        admMessage->command = DP_USER_CMD_DEL;
        (void) strcpy(userName, argv[2]);

        Message.type = DP_USER_ADM;
        Message.len  = sizeof (dp_user_adm_t) + strlen(userName) + 1;
        Message.data = admMessage;
        ADM_Send(&Message);

        Timeout.tv_nsec = 0;
        Timeout.tv_sec  = ADM_SEPROM_TIMEOUT;
        ADM_Recv(&Message, &Timeout, DP_USER_ADM_R, sizeof (dp_user_adm_r_t));

        admResponse = (dp_user_adm_r_t *)Message.data;
        if (admResponse->command != DP_USER_CMD_DEL) {
                wrong_response();
                exit(-1);
        }

        if (admResponse->status == DP_ERR_USER_NONE) {
                no_user();
                exit(-1);
        } else if (admResponse->status == DP_ERR_USER_BAD) {
                malformed_username();
                exit(-1);
        } else if (admResponse->status != 0) {
                (void) fprintf(stderr, "\n%s\n\n",
                    gettext("scadm: couldn't delete user"));
                exit(-1);
        }

        ADM_Free(&Message);
}


void
ADM_Process_usershow(int argc, char *argv[])
{
        static data_buffer_t    dataBuffer;
        rscp_msg_t              Message;
        struct timespec         Timeout;
        dp_user_adm_t           *admMessage;
        dp_user_adm_r_t         *admResponse;
        char                    *userName;
        char                    *permissions;
        char                    *passwd;
        int                     index;



        if ((argc != 2) && (argc != 3)) {
                (void) fprintf(stderr, "\n%s\n\n",
                    gettext("USAGE: scadm usershow [username]"));
                exit(-1);
        }

        ADM_Start();

        if (argc == 3) {
                admMessage = (dp_user_adm_t *)&dataBuffer;
                admMessage->command = DP_USER_CMD_SHOW;
                Message.type = DP_USER_ADM;
                Message.data = admMessage;

                if (strlen(argv[2]) > DP_USER_NAME_SIZE) {
                        max_username();
                        exit(-1);
                }
                userName = (char *)(&((char *)admMessage)[
                    sizeof (dp_user_adm_t)]);
                (void) strcpy(userName, argv[2]);
                admMessage->parm = DP_USER_SHOW_USERNAME;
                Message.len = sizeof (dp_user_adm_t) + strlen(userName) + 1;
                ADM_Send(&Message);

                Timeout.tv_nsec = 0;
                Timeout.tv_sec  = ADM_SEPROM_TIMEOUT;
                ADM_Recv(&Message, &Timeout,
                    DP_USER_ADM_R, sizeof (dp_user_adm_r_t));

                admResponse = (dp_user_adm_r_t *)Message.data;
                if (admResponse->command != DP_USER_CMD_SHOW) {
                        wrong_response();
                        exit(-1);
                }

                if (admResponse->status == DP_ERR_USER_NONE) {
                        no_user();
                        exit(-1);
                } else if (admResponse->status == DP_ERR_USER_BAD) {
                        malformed_username();
                        exit(-1);
                } else if (admResponse->status != 0) {
                        no_info();
                        exit(-1);
                }

                userName = &(((char *)admResponse)[
                    sizeof (dp_user_adm_r_t)]);
                permissions = &userName[strlen(userName)+1];
                passwd = &permissions[strlen(permissions)+1];
                show_header();
                (void) printf(" %-16s    %-15s    ", userName, permissions);
                if (strncmp(passwd, "Assigned", 12) == 0) {
                        (void) printf("%s\n\n", gettext("Assigned"));
                } else if (strncmp(passwd, "None", 12) == 0) {
                        (void) printf("%s\n\n", gettext("None"));
                } else {
                        (void) printf("%-12s\n\n", passwd);
                }
                ADM_Free(&Message);
        } else {
                show_header();
                for (index = 1; index <= DP_USER_MAX; index++) {
                        admMessage = (dp_user_adm_t *)&dataBuffer;
                        admMessage->command = DP_USER_CMD_SHOW;
                        admMessage->parm    = index;

                        Message.type = DP_USER_ADM;
                        Message.data = admMessage;
                        Message.len  = sizeof (dp_user_adm_t);
                        ADM_Send(&Message);

                        Timeout.tv_nsec = 0;
                        Timeout.tv_sec  = ADM_SEPROM_TIMEOUT;
                        ADM_Recv(&Message, &Timeout,
                            DP_USER_ADM_R, sizeof (dp_user_adm_r_t));

                        admResponse = (dp_user_adm_r_t *)Message.data;
                        if (admResponse->command != DP_USER_CMD_SHOW) {
                                wrong_response();
                                exit(-1);
                        }

                        if (admResponse->status == DP_ERR_USER_NONE) {
                                ADM_Free(&Message);
                                continue;
                        } else if (admResponse->status == DP_ERR_USER_BAD) {
                                malformed_username();
                                exit(-1);
                        } else if (admResponse->status != 0) {
                                no_info();
                                exit(-1);
                        }

                        userName = &(((char *)admResponse)[
                            sizeof (dp_user_adm_r_t)]);
                        permissions = &userName[strlen(userName)+1];
                        passwd = &permissions[strlen(permissions)+1];
                        (void) printf(" %-16s    %-15s    ",
                            userName, permissions);
                        if (strncmp(passwd, "Assigned", 12) == 0) {
                                (void) printf("%s\n", gettext("Assigned"));
                        } else if (strncmp(passwd, "None", 12) == 0) {
                                (void) printf("%s\n", gettext("None"));
                        } else {
                                (void) printf("%-12s\n", passwd);
                        }

                        ADM_Free(&Message);
                }
                (void) printf("\n");
        }
}


void
ADM_Process_userpassword(int argc, char *argv[])
{
        static data_buffer_t    dataBuffer;
        rscp_msg_t              Message;
        struct timespec         Timeout;
        dp_user_adm_t           *admMessage;
        dp_user_adm_r_t         *admResponse;
        char                    *userName;
        char                    *password;
        int                     passTry;


        /* Try to set password up to 3 times on Malformed password */
        passTry = 3;

        if (argc != 3) {
                (void) fprintf(stderr, "\n%s\n\n",
                    gettext("USAGE: scadm userpassword <username>"));
                exit(-1);
        }

        ADM_Start();

        if (strlen(argv[2]) > DP_USER_NAME_SIZE) {
                max_username();
                exit(-1);
        }

        admMessage = (dp_user_adm_t *)&dataBuffer;
        admMessage->command = DP_USER_CMD_PASSWORD;
        userName = (&((char *)admMessage)[sizeof (dp_user_adm_t)]);
        (void) strcpy(userName, argv[2]);
        password = (&((char *)admMessage)[sizeof (dp_user_adm_t) +
            strlen(userName) + 1]);

        for (;;) {
                ADM_Get_Password(password);

                Message.type = DP_USER_ADM;
                Message.len  = sizeof (dp_user_adm_t) + strlen(userName) +
                    strlen(password) + 2;
                Message.data = admMessage;
                ADM_Send(&Message);

                ADM_Destroy_Password(password);
                Timeout.tv_nsec = 0;
                Timeout.tv_sec  = ADM_SEPROM_TIMEOUT;
                ADM_Recv(&Message, &Timeout,
                    DP_USER_ADM_R, sizeof (dp_user_adm_r_t));

                admResponse = (dp_user_adm_r_t *)Message.data;
                if (admResponse->command != DP_USER_CMD_PASSWORD) {
                        wrong_response();
                        exit(-1);
                }

                if (admResponse->status == DP_ERR_USER_NONE) {
                        no_user();
                        exit(-1);
                } else if (admResponse->status == DP_ERR_USER_BAD) {
                        malformed_username();
                        exit(-1);
                } else if (admResponse->status == DP_ERR_USER_PASSWD) {
                        (void) fprintf(stderr, "\n%s\n\n",
                            gettext("scadm: malformed password\n"
                            "        A valid password is between 6 and 8 "
                            "characters,\n"
                            "        has at least two alphabetic characters, "
                            "and at\n"
                            "        least one numeric or special character. "
                            "The\n"
                            "        password must differ from the user's "
                            "login name\n"
                            "        and any reverse or circular shift of that "
                            "login\n"
                            "        name.\n"));
                        passTry--;
                        if (passTry > 0) {
                                ADM_Free(&Message);
                                continue;
                        } else
                                exit(-1);
                } else if (admResponse->status != 0) {
                        (void) fprintf(stderr, "\n%s\n\n",
                            gettext("scadm: couldn't change password"));
                        exit(-1);
                }

                /* password was changed successfully, get out of while */
                break;
        }

        ADM_Free(&Message);
}


void
ADM_Process_userperm(int argc, char *argv[])
{
        static data_buffer_t    dataBuffer;
        rscp_msg_t              Message;
        struct timespec         Timeout;
        dp_user_adm_t           *admMessage;
        dp_user_adm_r_t         *admResponse;
        char                    *userName;
        int                     permissions;
        int                     index;


        if ((argc != 3) && (argc != 4)) {
                userperm_usage();
                exit(-1);
        }

        if (argc == 3) {
                permissions = 0;
        } else {
                if ((strlen(argv[3]) > 4) || (strlen(argv[3]) < 1)) {
                        userperm_usage();
                        exit(-1);
                }

                permissions = 0;
                for (index = 0; index < strlen(argv[3]); index++) {
                        if ((argv[3][index] != 'c') &&
                            (argv[3][index] != 'C') &&
                            (argv[3][index] != 'u') &&
                            (argv[3][index] != 'U') &&
                            (argv[3][index] != 'a') &&
                            (argv[3][index] != 'A') &&
                            (argv[3][index] != 'r') &&
                            (argv[3][index] != 'R')) {
                                userperm_usage();
                                exit(-1);
                        }

                        if ((argv[3][index] == 'c') ||
                            (argv[3][index] == 'C')) {
                                /* See if this field was entered twice */
                                if ((permissions & DP_USER_PERM_C) != 0) {
                                        userperm_usage();
                                        exit(-1);
                                }
                                permissions = permissions | DP_USER_PERM_C;
                        }

                        if ((argv[3][index] == 'u') ||
                            (argv[3][index] == 'U')) {
                                /* See if this field was enetered twice */
                                if ((permissions & DP_USER_PERM_U) != 0) {
                                        userperm_usage();
                                        exit(-1);
                                }
                                permissions = permissions | DP_USER_PERM_U;
                        }

                        if ((argv[3][index] == 'a') ||
                            (argv[3][index] == 'A')) {
                                /* See if this field was enetered twice */
                                if ((permissions & DP_USER_PERM_A) != 0) {
                                        userperm_usage();
                                        exit(-1);
                                }
                                permissions = permissions | DP_USER_PERM_A;
                        }

                        if ((argv[3][index] == 'r') ||
                            (argv[3][index] == 'R')) {
                                /* See if this field was enetered twice */
                                if ((permissions & DP_USER_PERM_R) != 0) {
                                        userperm_usage();
                                        exit(-1);
                                }
                                permissions = permissions | DP_USER_PERM_R;
                        }
                }
        }

        ADM_Start();

        if (strlen(argv[2]) > DP_USER_NAME_SIZE) {
                max_username();
                exit(-1);
        }

        admMessage = (dp_user_adm_t *)&dataBuffer;
        admMessage->command = DP_USER_CMD_PERM;
        admMessage->parm    = permissions;
        userName   = (char *)(&((char *)admMessage)[sizeof (dp_user_adm_t)]);
        (void) strcpy(userName, argv[2]);

        Message.type = DP_USER_ADM;
        Message.len  = sizeof (dp_user_adm_t) + strlen(userName) + 1;
        Message.data = admMessage;
        ADM_Send(&Message);

        Timeout.tv_nsec = 0;
        Timeout.tv_sec  = ADM_SEPROM_TIMEOUT;
        ADM_Recv(&Message, &Timeout, DP_USER_ADM_R, sizeof (dp_user_adm_r_t));

        admResponse = (dp_user_adm_r_t *)Message.data;
        if (admResponse->command != DP_USER_CMD_PERM) {
                wrong_response();
                exit(-1);
        }

        if (admResponse->status == DP_ERR_USER_NONE) {
                no_user();
                exit(-1);
        } else if (admResponse->status == DP_ERR_USER_BAD) {
                malformed_username();
                exit(-1);
        } else if (admResponse->status != 0) {
                (void) fprintf(stderr, "\n%s\n\n",
                    gettext("scadm: couldn't change permissions"));
                exit(-1);
        }

        ADM_Free(&Message);
}


static void
ADM_Get_Password(char *password)
{
        static char             pass1[64];
        static char             pass2[64];
        static struct termios   newOpts;
        int                     passTry;
        int                     validPass;


        validPass = 0;
        passTry   = 3;

        if (signal(SIGINT, cleanup) == SIG_ERR) {
                (void) fprintf(stderr, "\n%s\n\n",
                    gettext("scadm: cleanup() registration failed"));
                exit(-1);
        }

        echoOff = 1;
        (void) tcgetattr(0, &oldOpts);
        newOpts = oldOpts;
        newOpts.c_lflag &= ~ECHO;
        (void) tcsetattr(0, TCSANOW, &newOpts);

        while ((passTry > 0) && (validPass == 0)) {
                passTry = passTry - 1;
                (void) printf("%s", gettext("Password: "));
                (void) scanf("%s", pass1);
                (void) printf("\n");
                (void) fflush(stdin);
                (void) printf("%s", gettext("Re-enter Password: "));
                (void) scanf("%s", pass2);
                (void) printf("\n");

                /* Truncate at 8 characters  */
                pass1[8] = pass2[8] = '\0';

                if ((strcmp(pass1, pass2) != 0) && (passTry > 0)) {
                        ADM_Destroy_Password(pass1);
                        ADM_Destroy_Password(pass2);
                        (void) fprintf(stderr, "%s\n\n",
                            gettext("Passwords didn't match, try again"));
                } else if ((strcmp(pass1, pass2) != 0) && (passTry <= 0)) {
                        ADM_Destroy_Password(pass1);
                        ADM_Destroy_Password(pass2);
                        (void) fprintf(stderr, "\n%s\n\n",
                            gettext("scadm: ERROR, passwords didn't match"));
                        (void) tcsetattr(0, TCSANOW, &oldOpts);
                        exit(-1);
                } else {
                        validPass = 1;
                }
        }

        (void) tcsetattr(0, TCSANOW, &oldOpts);
        echoOff = 0;
        (void) strcpy(password, pass1);
        ADM_Destroy_Password(pass1);
        ADM_Destroy_Password(pass2);
}


static void
cleanup()
{
        if (echoOff)
                (void) tcsetattr(0, TCSANOW, &oldOpts);

        exit(-1);
}


static void
ADM_Destroy_Password(char *password)
{
        int index;

        for (index = 0; index < strlen(password); index++)
                password[index] = 0x1;
}


static void
max_username()
{
        (void) fprintf(stderr,
            gettext("\nscadm: maximum username length is %d\n\n"),
            DP_USER_NAME_SIZE);
}


static void
malformed_username()
{
        (void) fprintf(stderr,
            "\n%s\n\n", gettext("scadm: malformed username"));
}


static void
wrong_response()
{
        (void) fprintf(stderr, "\n%s\n\n",
            gettext("scadm: SC returned wrong response"));
}


static void
no_user()
{
        (void) fprintf(stderr,
            "\n%s\n\n", gettext("scadm: username does not exist"));
}


static void
no_info()
{
        (void) fprintf(stderr, "\n%s\n\n",
            gettext("scadm: couldn't get information on user"));
}


static void
userperm_usage()
{
        (void) fprintf(stderr, "\n%s\n\n",
            gettext("USAGE: scadm userperm <username> [cuar]"));
}


static void
show_header()
{
        int i;
        int usernLen = strlen(gettext("username"));
        int permLen = strlen(gettext("permissions"));
        int pwdLen = strlen(gettext("password"));

        (void) printf("\n");
        (void) putchar(' ');
        (void) printf("%s", gettext("username"));
        for (i = 0; i < (20 - usernLen); i++)
                (void) putchar(' ');

        (void) printf("%s", gettext("permissions"));
        for (i = 0; i < (19 - permLen); i++)
                (void) putchar(' ');

        (void) printf("%s\n", gettext("password"));

        (void) putchar(' ');
        for (i = 0; i < usernLen; i++)
                (void) putchar('-');
        for (; i < 20; i++)
                (void) putchar(' ');

        for (i = 0; i < permLen; i++)
                (void) putchar('-');
        for (; i < 19; i++)
                (void) putchar(' ');

        for (i = 0; i < pwdLen; i++)
                (void) putchar('-');
        (void) printf("\n");
}