2013年1月14日 星期一

[C] 一行指令建立帳號、更新密碼 (需setuid) @ Ubuntu 12.04

最近有需求要幫系統加入新增帳號、修改帳密的流程,所以想著想著,就蹦出了一支 C 程式,透過 setuid 的方式,終於可以完成這項工作 (經高手指點,bash 無法被 setuid 使用,也就是設定完後無法達成想要的結果,可以在 script 裡打 id 指令)


相關 Unix 指令回顧:



  • 一行指令新增帳號


    • $ sudo adduser --quiet --gecos "" --disabled-login --no-create-home --shell "/usr/sbin/nologin" tester


  • 一行指令更新密碼


    • $ echo "tester:password" | chpasswd


  • 檢查使用者是否存在


    • $ getent passwd tester



程式碼:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#include <sys/types.h>
#include <unistd.h>


#define CMD_ADDUSER "sudo adduser --quiet --gecos \"\" --disabled-login --no-create-home --shell \"/usr/sbin/nologin\" "
#define CMD_CHECK_USER_EXISTS "getent passwd"
#define MAX_BUFFER_LINE 1024
int main(int argc, char *argv[])
{
   char buf[MAX_BUFFER_LINE+1], pass[MAX_BUFFER_LINE+1], *cmd;
   FILE *fp;
   setuid(0); // use root
   //system("id");
   if( argc < 3 )
   {
      fprintf( stderr, "Usage> %s username [ - | password]\n\t%s username -\t\t(read password from stdin)\n\t%s username password\n\n\tothers: sudo chown root %s && sudo chmod 4755 %s\n" , argv[0], argv[0], argv[0] , argv[0], argv[0] );
      exit(1);
   }


   memset( buf, 0, MAX_BUFFER_LINE + 1);
   memset( pass, 0, MAX_BUFFER_LINE + 1);
   if( argv[2][0] != '-' )
   {
      strncpy( pass, argv[2], MAX_BUFFER_LINE );
      pass[MAX_BUFFER_LINE] = '\0';
   }
   else if( !feof( stdin ) && fgets( pass, MAX_BUFFER_LINE, stdin ) > 0 )
   {
      //printf("Pass:[%s]\n",pass);
   }


   if( strlen(pass) < 1 )
   {
      fprintf( stderr, "Error @ Init: password is empty\n" );
      exit(1);
   }

   // check account exists
   cmd = buf;
   snprintf( buf, MAX_BUFFER_LINE, "%s %s", CMD_CHECK_USER_EXISTS, argv[1] );
   fp = popen( cmd , "r" );


   memset( buf, 0, MAX_BUFFER_LINE + 1);
   fgets( buf, MAX_BUFFER_LINE, fp );
   pclose(fp);


   if( !strlen(buf) ) // create the account if not exists
   {
      // add account
      memset( buf, 0, MAX_BUFFER_LINE + 1);
      cmd = buf;
      snprintf( buf, MAX_BUFFER_LINE, "%s %s", CMD_ADDUSER, argv[1] );
      pclose( popen( cmd , "r" ) );


      // query the account
      memset( buf, 0, MAX_BUFFER_LINE + 1);
      cmd = buf;
      snprintf( buf, MAX_BUFFER_LINE, "%s %s", CMD_CHECK_USER_EXISTS, argv[1] );
      fp = popen( cmd , "r" );
      memset( buf, 0, MAX_BUFFER_LINE + 1);
      fgets( buf, MAX_BUFFER_LINE, fp );
      pclose(fp);

      if( !strstr( buf, argv[1] ) ) // user is not created
      {
         printf("Error @ create an account: user cannot be created\n");
         exit(1);
      }


      // change password
      memset( buf, 0, MAX_BUFFER_LINE + 1);
      cmd = buf;
      snprintf( buf, MAX_BUFFER_LINE, "echo \"%s:%s\" | chpasswd ", argv[1] , pass );
      fp = popen( cmd , "r" );
      memset( buf, 0, MAX_BUFFER_LINE + 1);
      fgets( buf, MAX_BUFFER_LINE, fp );
      pclose(fp);
      if( !strlen(buf) )
         printf("OK\n");
   }
   else if( strstr( buf, "/bin/false" ) || strstr( buf, "/nologin" ) ) // change password
   {
      // change password
      memset( buf, 0, MAX_BUFFER_LINE + 1);
      cmd = buf;
      snprintf( buf, MAX_BUFFER_LINE, "echo \"%s:%s\" | chpasswd ", argv[1] , pass );
      fp = popen( cmd , "r" );
      memset( buf, 0, MAX_BUFFER_LINE + 1);
      fgets( buf, MAX_BUFFER_LINE, fp );
      pclose(fp);
      if( !strlen(buf) )
         printf("OK\n");
   }
   else
   {
      printf("SKIP @ cannot change the password for '%s'.\n", argv[1]);
   }
   return 0;
}


暫時把這隻程式定位:



  • 可以新增 nologin 帳號

  • 可以修改 nologin 帳號的密碼


用法:


$ gcc main.c
$ sudo chown root ./a.out && sudo chmod 4755 ./a.out
$ ./a.out new_account new_password


若要在安全一下,可以在設定 uid 範圍,以避免改到一些系統帳號。


沒有留言:

張貼留言