/* remote yppasswd type program
 * lets you change username, password, gecos and/or shell
 * remotely via the yppasswd daemon.
 * (note daemon may not accept all of your changes)
 * 
 *  cc source.c -lrpcsvc
 *  progname ypmaster ypdomain
 */

#include <signal.h>
#include <rpc/rpc.h>
#include <stdio.h>
#include <pwd.h>
#include <rpcsvc/yppasswd.h>
#include <rpcsvc/yp_prot.h>

#define TIMEOUT 15

extern char *get_yp_map();

char *split(s)
char *s;
{
  while(*s!='\0' && *s!=':') s++;
  if(*s =='\0') return s;
  *s='\0';
  return(s+1);
}

changes(p)
struct passwd *p;
{
  int done=0,choice;
  char s[100],s2[100];

  while(!done)
    {
      printf("0. quit\n");
      printf("1. name\n");
      printf("2. password\n");
      printf("3. gecos\n");
      printf("4. shell\n");
      printf("choice> ");
      fflush(stdout);
      scanf("%d",&choice);
      switch(choice)
        {
        case 0:
          done++;
          break;
        case 1:
          printf("New name: ");
          fflush(stdout);
          scanf("%s",p->pw_name);
          break;
        case 2:
          printf("New pass: ");
          fflush(stdout);
          scanf("%s",s);
          s[8]='\0';
          /* so we dont have a random salt.. who cares */
          strcpy(p->pw_passwd,crypt(s,"AE"));
          break;
        case 3:
          printf("New finger info: ");
          scanf("%*c");     /* get rid of previous \n still in buffer */
          strcpy(p->pw_gecos,gets(s));
          break;
        case 4:
          printf("New shell: ");
          fflush(stdout);
          scanf("%s",s);
          strcpy(p->pw_shell,s);
          break;
        default:
          printf("Invalid Choice.\n");
          break;
        }
    }
}

getpw(p,st)   /* put string st into passwd structure */
struct passwd *p;
char *st;
{
  char *s,*t;

  s=split(st);
  strcpy(p->pw_name, st);
  t=split(s);
  strcpy(p->pw_passwd,s);
  s = split(t);
  p->pw_uid = atoi(t);
  t = split(s);
  p->pw_gid = atoi(s);
  s = split(t);
  strcpy(p->pw_gecos,t);
  t = split(s);
  strcpy(p->pw_dir,s);
  s=split(t);
  strcpy(p->pw_shell,t);
  p->pw_age = NULL;
  p->pw_comment = NULL;
}

void timeout();
char *getpass();

main(argc,argv)
char **argv;
int argc;
{
  struct yppasswd yppasswd;
  struct passwd p;
  int len,ok,ans;
  enum clnt_stat errcode;
  char temp[100],a[100],b[20],c[100],d[100],e[50];
  char space[100];
  char *s;
  struct ypreq_key key;
  struct ypresp_val answer;
  char *domain,*master;
  char *pass;

  if(argc!=3)
    {
      printf("Usage: %s server domain\n",argv[0]);
      exit(1);
    }
  master=argv[1];
  domain=argv[2];

  answer.valdat.dptr = space;   /* where our answer will be */

  p.pw_name   = a;     /* we need space! */
  p.pw_passwd = b;
  p.pw_gecos  = c;
  p.pw_dir    = d;
  p.pw_shell  = e;

  printf("Enter account name : ");
  scanf("%s",temp);

  key.domain = domain;
  key.map = "passwd.byname";
  key.keydat.dptr = temp;
  key.keydat.dsize = strlen(temp);

  signal(SIGALRM,timeout);
  alarm(TIMEOUT);
  errcode = callrpc( master,YPPROG, YPVERS, YPPROC_MATCH,
                     xdr_ypreq_key,(caddr_t) &key,
                     xdr_ypresp_val, &answer);
  alarm(0);
  if ( errcode != RPC_SUCCESS)
    print_rpc_err(errcode);
  if (answer.status == TRUE )
    {   /* we have a match */
      len = answer.valdat.dsize;
      answer.valdat.dptr[len] = '\0';   /* null terminate */
      getpw(&p,answer.valdat.dptr);
      print_pwd(p);
    }
  else
    {
      printf("User %s not found.\n",temp);
      exit(1);
    }
  printf("\n\n");

  pass=getpass("Password:");
  /*  if(strlen(p.pw_passwd)!=0)
      if (strcmp(crypt(pass,p.pw_passwd),p.pw_passwd)!=0) {
        printf("Bad password.  Not even gonna bother.\n");
        exit(1);
      }    
  */

  changes(&p);
  print_pwd(p);
  printf("Is this ok? [y/n] : ");
  scanf("%*c");   /* flush last <enter> */
  gets(temp);
  if(temp[0]!='y') return;

  yppasswd.oldpass = pass;
  yppasswd.newpw = p;

  /* All the work is done here, now we try to actually do it */
  ans = callrpc(master, YPPASSWDPROG, YPPASSWDVERS,
                YPPASSWDPROC_UPDATE, xdr_yppasswd, &yppasswd,
                xdr_int, &ok);
  if(ans!=0)
    {
      fprintf(stderr, "RPC call didnt go through.\n");
      exit(1);
    }
  if(ok==1)
    {
      fprintf("Remote site wouldnt change pw entry (wrong pw?)\n");
    }
  if(ok!=0)
    {
      decodeans(ok,master);
      exit(1);
    }

}


#define MAXMSG 17
char *msgs[]=
  {
    "No error",                             /*0*/
    "Error from pre 4.1 version",           /*1*/
    "Password incorrect",   /*2*/ /*really login incorrect but why say so*/
    "No changeable fields were changed",   /*3*/
    "No password in adjunct",   /*4*/
    "Bad password in adjunct",   /*5*/
    "Inconsistency in adjunct",   /*6*/
    "Password incorrect",   /*7*/
    "Password file busy -- try again later",   /*8*/
    "Password temp file open error -- contact system administrator",   /*9*/
    "Password temp file fdopen error -- contact system administrator",   /*10*/
    "Password adjunct file fopen error -- contact system administrator",   /*11*/
    "Password file fopen error -- contact system administrator",   /*12*/
    "Password temp file fputs failed; disk partition may be full on NIS master! -- contact system administrator",   /*13*/
    "Password temp file ferror is set; disk partition may be full on NIS master! -- contact system administrator",   /*14*/
    "Password temp file fflush failed; disk partition may be full on NIS master! -- contact system administrator",   /*15*/
    "Password adjunct file rename failed; disk partition may be full on NIS master! -- contact system administrator",   /*16*/
    "Password file rename failed; disk partition may be full on NIS master! -- contact system administrator",   /*17*/
  };

decodeans(ok, master)
char *master;
int ok;
{
  if (ok <0 || ok > MAXMSG )
    fprintf(stderr, "Remote %s error %d\n",master, ok);
  else
    fprintf(stderr,"Error from %s: %s \n",master, msgs[ok]);
}

print_pwd(p)
struct passwd p;
{
  printf("%s:%s:%d:%d:%s:%s:%s\n",
         p.pw_name,p.pw_passwd,p.pw_uid,p.pw_gid,
         p.pw_gecos,p.pw_dir,p.pw_shell);
}


print_rpc_err(errcode)
{
  fprintf(stderr, "%s\n",clnt_sperrno(errcode));
  exit(1);
}

void timeout()
{
  printf("RPC request (callrpc) timed out.\n");
  exit(1);
}
/*                    www.hack.co.za              [2000]*/