• 使用crypt生成用户密码-Tested on RedHat & SuSE Platform


    近期做EasyCluster,需要创建用户,要求在Linux上能创建一个用户帐号,很自然想到了后台程序调用useradd命令行来完成,但众所周 知,密码是个麻烦事。查看了 useradd的手册,有个-p password 选项可以在创建的时候就指定密码,但要求这里的密码是已经加过密的,这就要求用crypt函数进行加密,然后再放入命令行。故测试了一下,写了一段测试代 码,用来生成密码:

    Code: Select all
    #define _XOPEN_SOURCE
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>

    int main()
    {
        char key[] = "666666";
        printf("encrypted password is: %s\n", crypt(key, "3a"));
        return 0;
    }


    这 里就能生成666666的密码。要注意的是,首先必须定义 _XOPEN_SOURCE ,这是crypt的手册中要求的;第二,crypt函数的第一个参数是明文密码,第二个参数叫做“salt”,其实就是一个加密的密钥,有两个字符组成, 字符的取值可以是“a-zA-Z0-9./” 这些,具体请看手册。

    然后用 useradd -p <encrypted password> <username> 就可以生成一个我们指定密码的帐号了。

    CAUTION: 用户登录和上述过程是一个相反的过程,但难度在于不知道salt。这里不同的加密方法有不同的规则,比如某些加密方法,加密出来的密文的头两个字母就是 salt,有些则不是。在所有的机密方法上,glibc提供了crypt这个调用,屏蔽了多种加密算法的复杂性,这应该就是Linux的PAM机制。所 以,用户登录的时候,首先要根据加密方法在密文中取出salt,然后调用crypt生成密文,再对比,即可!一种加密方法不行,再试第二种。这里有我们 EasyCluster的用户登录后台验证的代码,在RedHat和SuSE(SuSE和RedHat的加密方法就不同,不过对于创建密码来说,两者都是 一样的,都是调用crypt嘛,如上所述)中都试验通过了:

    Code: Select all
    #define _XOPEN_SOURCE
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>

    #include "easy_s.h"
    #include "common.h"

    //  you need link your object file like this:
    //                        gcc -o xx  xxx.c  -lcrypt
    //int authenticate_user(char *username, char *key);

    int authenticate_user(char *username, char *key)
    {
        const int buffer_len = 512;
        const char filename[50] = "/etc/shadow";
        char *dataline = (char *)malloc(buffer_len);
        if (dataline == NULL){
            message_log("authenticate_user() error: failed to allocate space for user data buffer.");
            return -2;
        }
       
        FILE *fp = fopen(filename, "r");
        if (fp == NULL){
            free(dataline);
            //fprintf(stderr, "failed to open user account file.\n");
            return -1;
        }

        while (fgets(dataline, buffer_len, fp)){
            if (strstr(dataline, username)){   
                /*
        char *crypt(const char *key, const char *salt).
         If  salt is a character string starting with the three characters "$1$"
         followed by at most eight characters, and optionally  terminated 
         by  "$",  then instead of using the DES machine, the glibc crypt
           function uses an MD5-based algorithm,  and  outputs  up  to  34  bytes,
           namely  "$1$<string>$", where "<string>" stands for the up to 8 charac-
           ters following "$1$" in the salt, followed by 22 bytes chosen from  the
           set [a-zA-Z0-9./].
                */
                char *line = strstr(dataline, "$1$");
                char *t;
                /*if ((line == NULL) || (strlen(line) < 4)){
                    free(dataline);
                    fclose(fp);
                    return -4;
                }
                */

                if (line == NULL ){
                    line = strchr(dataline, ':');
                    if (line == NULL){
                        free(dataline);
                        fclose(fp);
                        return -4;
                    }
                    t = strchr((line+1), ':');           
                    if (t == NULL){
                        free(dataline);
                        fclose(fp);
                        return -4;
                    }
                    *t = '\0';
                    char salt_1[16];
                    salt_1[0] = line[1];salt_1[1] = line[2];salt_1[2] = '\0';
                    char *pass = crypt(key, salt_1);
                    if (pass == NULL){
                        free(dataline);
                        fclose(fp);
                        return -4;
                    }
                    if (strcmp((line+1), pass) == 0){
                        free(dataline);
                        fclose(fp);
                        return 0;
                    }else{
                        free(dataline);
                        fclose(fp);
                        return -5;
                    }
                }
                if (strlen(line) < 4){
                    free(dataline);
                    fclose(fp);
                    return -4;
                }
               
                t =strstr((line+3), ":");
                if (t == NULL){
                    free(dataline);
                    fclose(fp);
                    return -4;
                }
                t[0] = '\0';
                t = strstr((line+3), "$");
                if (t == NULL){
                    free(dataline);
                    fclose(fp);
                    return -4;
                }
               
                char salt[50];
                memcpy(salt, line, t-line+1);
                char *encrypt_str = crypt(key, salt);
                if (encrypt_str == NULL){
                    free(dataline);
                    fclose(fp);
                    return -5;
                }
                if (strcmp(encrypt_str, line) == 0){
                    free(dataline);
                    fclose(fp);
                    return 0;
                }
            }
        }

        free(dataline);
        fclose(fp);
        return -4;
    }
    同上,使用usermod命令的-p选项就可以修改用户密码。如:usermod -p <encrypted password> username 即可
  • 相关阅读:
    redisTemplate
    HttpURLConnection下载文件流
    Quartz集成springMVC 的方案二(持久化任务、集群和分布式)
    https请求
    将一个 JavaBean 对象转化为一个 Map
    Redis实现简单消息队列
    Spring Boot RestTemplate文件上传
    获取java栈异常
    获取 *.properties配置文件内容
    java格式化json串
  • 原文地址:https://www.cnblogs.com/super119/p/2005605.html
Copyright © 2020-2023  润新知