/* 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);
}

