/* ** File Name: FINGERD.C ** Product: TCPware for OpenVMS ** Version: V5.6 ** Edit Level: 25 ** ** Copyright (c) 2001, 2002 by ** Process Software LLC ** Framingham, Massachusetts ** ** This software is furnished under a license for use on a ** single computer system and may be copied only with the ** inclusion of the above copyright notice. This software, or ** any other copies thereof, may not be provided or otherwise ** made available to any other person except for use on such ** system and to one who agrees to these license terms. Title ** to and ownership of the software shall at all times remain ** in Process Software LLC's name. ** ** The information in this document is subject to change ** without notice and should not be construed as a commitment ** by Process Software LLC. Process Software LLC assumes no ** responsibility for any errors that may appear in this document. ** ** Note: ** This module is provided "as is" for example purposes only. ** It was provided by K. Wampler and implements a FINGER ** server (see RFC-1196). Updated by Hunter Goatley. ** ** ** To build on a VAX with VAX C: ** $ CC FINGERD.C ** $ LINK FINGERD,SYS$INPUT/OPTIONS ** TCPWARE:UCX$IPC.OLB/LIBRARY ** SYS$SHARE:VAXCRTL.EXE/SHARE ** ** ** To build on an Alpha or VAX with DEC C: ** $ CC/PREFIX=ALL FINGERD.C ** $ LINK FINGERD,SYS$INPUT/OPTIONS ** SYS$SHARE:TCPWARE_SOCKLIB_SHR/SHARE ** ** ** To use: ** Use the NETCU ADD SERVICE and (optionally) the ADD ACCESS ** commands to "start" the server. The ADD ACCESS commands ** can be used to restrict access to the finger server to ** specific hosts or networks. ** ** For example: ** $ NETCU ADD SERVICE FINGER TCP FINGERD - ** /PRIV=(NOSAME,NETMBX,TMPMBX,WORLD,SYSPRV) - ** /ACCESS= ** (and other qualifiers as you may want) ** ** Don't forget to add these commands to the TCPWARE:SERVERS.COM ** file so that the server is started whenever TCPware is started. */ #include #include #include #include #include #include #include #include #include #include /* ** For the routines declared in and , make sure they're ** prefixed with "DECC$". */ #if defined(__DECC) && defined(__DECC_VER) && (__DECC_VER > 50300000) #pragma extern_prefix save #pragma extern_prefix "DECC$" #include #include #pragma extern_prefix restore #else #include #include #endif /* ** Define these since PSCANDEF doesn't exist on some systems. */ #define PSCAN$_NODE_CSID 12 #define PSCAN$_MODE 11 #define PSCAN$_USERNAME 23 #define PSCAN$M_EQL 1024 #define PSCAN$M_WILDCARD 256 #define PSCAN$M_CASE_BLIND 512 #ifndef NULL #define NULL 0 #endif #define PORT 79 long int status,client_ipadr,par,len; int channel; int nolisten = 1; #ifdef __DECC #pragma __member_alignment save #pragma __nomember_alignment #endif struct iosb {short int status; short unsigned byte_count; long int devdata;} net_iosb; struct itemlist {short int param_id; long int param_val;} ecb[2]; struct user_str { struct user_str *link; char username[12+1]; char owner[31+1+1]; int newmail; }; struct { unsigned short length; unsigned short icode; char *bufadr; unsigned short *lenadr; } trn_list[] = { { 0, 0, 0, 0 }, /* Fill in at run-time */ { 0, 0, 0, 0 } }; #ifdef __DECC #pragma __member_alignment restore #endif struct descriptor {long int len; char *adr;} ecb_desc; char buffer[512],client_arg[512]; struct user_str *user_lh = 0; static $DESCRIPTOR (cn_desc, "_TCP0:"); char lnode[32+1]; static $DESCRIPTOR (lnmsys_dsc, "LNM$SYSTEM"); static $DESCRIPTOR (nodedsc, "SYS$NODE"); /* Forward routine prototypes */ int init_iplist(void); int upper_case(char *); int valid_ipadr(int); int list_procs(char *); int list_user(char *); int net_msg(char *); int close_mailfile(void); int mail_check(char *); int convert_time(char *, char *); int open_mailfile(char *, char *); extern int tcpware_server(int, int *); /******************************************************************************/ main(long int argc, char **argv) { struct user_str *up; char *cp; int i; init_iplist(); len = 0; trn_list[0].length = sizeof(lnode)-1; trn_list[0].icode = LNM$_STRING; trn_list[0].bufadr = (char *) &lnode; trn_list[0].lenadr = (unsigned short *) &len; sys$trnlnm (0, &lnmsys_dsc, &nodedsc, 0, &trn_list); if (len > 2) len -= 2; lnode[len] = 0; if (tcpware_server(1,&channel) == 0) goto connected; nolisten = 0; /* Assign channel to TCP0 */ assign_channel: while (up = user_lh) { user_lh = up->link; free(up); } status = sys$assign(&cn_desc,&channel,NULL,NULL); if (status != SS$_NORMAL) {printf("\n%%FINGERD-F-ASSIGN, failed to assign channel to _TCP0:\n"); exit(status);} /* Perform "passive open" on finger port */ passive_open: ecb[0].param_id = 1; ecb[0].param_val = PORT; ecb[1].param_id = 7; ecb[1].param_val = -1; /* Allow multiple passive opens on same port */ ecb_desc.len = sizeof(ecb); ecb_desc.adr = (char *) &ecb; status = sys$qiow(NULL,channel, (IO$_SETMODE | IO$M_CTRL | IO$M_STARTUP | 0x800), &net_iosb,NULL,NULL, NULL,&ecb_desc,NULL,NULL,NULL,NULL); if (net_iosb.status != SS$_NORMAL) {printf("\n%%FINGERD-F-LISTEN, listen failed\n"); exit(net_iosb.status);} connected: /* Retrieve the client's argument */ cp = buffer; while (cp != &buffer[sizeof(buffer)]) { status = sys$qiow(NULL,channel,IO$_READVBLK,&net_iosb,NULL,NULL, cp,&buffer[sizeof(buffer)]-cp,NULL,NULL,NULL,NULL); if ((!(status & 1)) || (!(net_iosb.status & 1))) goto shutdown; for (i=0; ((inext = 0; /* ** Note: You can enter access restrictions here. However, it is ** probably best to use the NETCU ADD ACCESS_LIST command to ** restrict access (since changes do not require you to edit ** and rebuild the server). ** ** The following "iplist_entry" call allows access from any host ** on the 223.42.95 network. */ /* iplist_entry("223.42.95.0","255.255.255.0"); */ } iplist_entry(char *ipaddr_txt, char *ipmask_txt) { iplist_elem->ipmask = (inet_addr(ipmask_txt)); iplist_elem->ipadr = (inet_addr(ipaddr_txt)) & iplist_elem->ipmask; iplist_elem->next = (struct ip_val *) malloc(sizeof(struct ip_val)); iplist_elem = iplist_elem->next; iplist_elem->next = 0; } /* Validate an incoming IP address against the linked list of valid addresses */ valid_ipadr(int adr) { iplist_elem = iplist_head; if (iplist_elem->next == 0) return(1); /* no list, allow all */ while (iplist_elem->next != 0) {if ((adr & iplist_elem->ipmask) == iplist_elem->ipadr) return(1); iplist_elem = iplist_elem->next;} return(0); } /* List processes on the VMScluster */ #include #include #include #ifdef __DECC #pragma __member_alignment save #pragma __nomember_alignment #endif struct jpi_item {short int len; short int code; char *buf; short int *retlen;} jpi_list[7]; struct uai_item {short int len; short int code; char *buf; short int *retlen;} uai_list[3]; struct ctx_item {short int len; short int code; long int value; long int flags;} ctx_list[4]; struct syi_item {short int len; short int code; char *buf; short int *retlen;} syi_list[4]; struct descriptor un_desc; struct var_string {char len; char string[80];} owner; #ifdef __DECC #pragma __member_alignment restore #endif long int pid, pid_len, un_len, ll_len, on_len, context, mail_count; long int tt_len, pd_len, pn_len; long int csid, csid_len, nn_len; long lastlogin[2], curtime[2], day; long int header_flag, wild_csid; char username[80],ll_string[80],search_name[80],nodename[80]; char terminal[132],accpornam[80],phydevnam[32],when[32]; char msgbuf[512]; static char *dayofweek[] = { "Mon","Tue","Wed","Thu","Fri","Sat","Sun" }; static unsigned long curday; static unsigned long logday; list_procs(char *user_arg) { struct user_str *up; strcpy(search_name,"*"); strcat(search_name,user_arg); strcat(search_name,"*"); open_mailfile("VMSMAIL_PROFILE","SYS$SYSTEM:.DATA"); syi_list[0].len = 4; syi_list[0].code = SYI$_NODE_CSID; syi_list[0].buf = (char *) &csid; syi_list[0].retlen= (short int *) &csid_len; syi_list[1].len = sizeof(nodename); syi_list[1].code = SYI$_NODENAME; syi_list[1].buf = (char *) &nodename; syi_list[1].retlen= (short int *) &nn_len; syi_list[2].len = 0; syi_list[2].code = 0; /* terminate item list */ header_flag = 0; wild_csid = -1; get_node: nn_len = 0; status = sys$getsyi(0,&wild_csid,0,&syi_list,0,0,0); if ((status == SS$_NOMORENODE) && (csid == 0)) status = SS$_NORMAL; if (status != SS$_NORMAL) {close_mailfile(); return(header_flag); } nodename[nn_len] = 0; ctx_list[0].len = 0; ctx_list[0].code = PSCAN$_NODE_CSID; ctx_list[0].value = csid; ctx_list[0].flags = PSCAN$M_EQL; ctx_list[1].len = 0; ctx_list[1].code = PSCAN$_MODE; ctx_list[1].value = JPI$K_INTERACTIVE; ctx_list[1].flags = PSCAN$M_EQL; ctx_list[2].len = strlen(search_name); ctx_list[2].code = PSCAN$_USERNAME; ctx_list[2].value = (long int) &search_name; ctx_list[2].flags = PSCAN$M_WILDCARD | PSCAN$M_CASE_BLIND; ctx_list[3].len = 0; ctx_list[3].code = 0; /* terminate item list */ context = 0; status = sys$process_scan(&context,&ctx_list); jpi_list[0].len = 4; jpi_list[0].code = JPI$_PID; jpi_list[0].buf = (char *) &pid; jpi_list[0].retlen = (short int *) &pid_len; jpi_list[1].len = sizeof(username); jpi_list[1].code = JPI$_USERNAME; jpi_list[1].buf = (char *) &username; jpi_list[1].retlen = (short int *) &un_len; jpi_list[2].len = sizeof(lastlogin); jpi_list[2].code = JPI$_LOGINTIM; jpi_list[2].buf = (char *) &lastlogin; jpi_list[2].retlen = (short int *) &ll_len; jpi_list[3].len = sizeof(terminal); jpi_list[3].code = JPI$_TERMINAL; jpi_list[3].buf = (char *) &terminal; jpi_list[3].retlen = (short int *) &tt_len; #ifndef JPI$_TT_PHYDEVNAM #define JPI$_TT_PHYDEVNAM 812 #endif #ifndef JPI$_TT_ACCPORNAM #define JPI$_TT_ACCPORNAM 813 #endif jpi_list[4].len = sizeof(phydevnam); jpi_list[4].code = JPI$_TT_PHYDEVNAM; jpi_list[4].buf = (char *) &phydevnam; jpi_list[4].retlen = (short int *) &pd_len; jpi_list[5].len = sizeof(accpornam); jpi_list[5].code = JPI$_TT_ACCPORNAM; jpi_list[5].buf = (char *) &accpornam; jpi_list[5].retlen = (short int *) &pn_len; jpi_list[6].len = 0; jpi_list[6].code = 0; /* terminate item list */ uai_list[0].len = sizeof(owner); uai_list[0].code = UAI$_OWNER; uai_list[0].buf = (char *) &owner; uai_list[0].retlen = (short int *) &on_len; uai_list[1].len = 0; uai_list[1].code = 0; /* terminate item list */ get_pid: pid = 0; lastlogin[0] = 0; lastlogin[1] = 0; status = sys$getjpiw(0,&context,0,&jpi_list,0,0,0); if (status == SS$_NONEXPR) goto get_pid; if (status == SS$_SUSPENDED) status = SS$_NORMAL; if ((status != SS$_NORMAL) || (pid == 0)) {sys$process_scan(&context,0); if (csid == 0) return(header_flag); goto get_node;} username[un_len] = 0; un_desc.len = strlen(username); un_desc.adr = (char *) &username; terminal[tt_len] = 0; phydevnam[pd_len] = 0; if (pd_len) { if ((strcmp(terminal,phydevnam) == 0) || ((phydevnam[0] == '_') && (strcmp(terminal,&phydevnam[1]) == 0))) pd_len = 0; } if (pd_len) sprintf(terminal,"%s (%s)",terminal,phydevnam); accpornam[pn_len] = 0; if (pn_len) sprintf(terminal,"%s (%s)",terminal,accpornam); up = user_lh; while (up) { if (strcmp(username,up->username) == 0) break; up = up->link; } if (up == 0) { status = sys$getuai(0,0,&un_desc,&uai_list,0,0,0); if (!(status & 1)) goto get_pid; owner.string[owner.len] = 0; mail_count = mail_check((char *)&username); up = malloc(sizeof(struct user_str)); if (up) { up->link = user_lh; user_lh = up; strcpy(up->username,username); strcpy(up->owner,owner.string); if (mail_count > 999) mail_count = 999; up->newmail = mail_count; } } else { mail_count = up->newmail; strcpy(owner.string,up->owner); } if (header_flag == 0) { sys$gettim(&curtime); convert_time((char *) &curtime, (char*) &ll_string); lib$day(&curday,&curtime); if (csid == 0) { sprintf(msgbuf,"Status of node %s at %s\n%s\n", lnode,ll_string, " Username Name New Mail When Terminal"); } else { sprintf(msgbuf,"Status of VMScluster on node %s at %s\n%s\n", lnode,ll_string, " Username Node Name New Mail When Terminal"); } net_msg(msgbuf); header_flag = 1; } if ((lastlogin[0] == 0) && (lastlogin[1] == 0)) { strcpy(when,"suspended"); } else { convert_time((char *)&lastlogin, (char *) &ll_string); lib$day(&logday,&lastlogin); if (curday - logday < 7) { lib$day_of_week(&lastlogin,&day); sprintf(when,"%-3.3s %-5.5s",dayofweek[day-1],&ll_string[12]); } else { sprintf(when,"%-7.7s%-2.2s",&ll_string[0],&ll_string[9]); } } if (mail_count < 1) mail_count = 0; if (csid == 0) { sprintf(msgbuf,"%-12.12s %-24.24s %3d %-9.9s %.28s\n", username,owner.string,mail_count,when,terminal); } else { sprintf(msgbuf,"%-12.12s %-6.6s %-24.24s %3d %-9.9s %.21s\n", username,nodename,owner.string,mail_count,when,terminal); } net_msg(msgbuf); goto get_pid; } /* Attempt to list user who's not logged in from the UAF */ list_user(char *user_arg) { uai_list[0].len = sizeof(owner); uai_list[0].code = UAI$_OWNER; uai_list[0].buf = (char *) &owner; uai_list[0].retlen = (short int *) &on_len; uai_list[1].len = sizeof(lastlogin); uai_list[1].code = UAI$_LASTLOGIN_I; uai_list[1].buf = (char *) &lastlogin; uai_list[1].retlen = (short int *) &ll_len; uai_list[2].len = 0; uai_list[2].code = 0; /* terminate item list */ un_desc.len = strlen(user_arg); un_desc.adr = user_arg; if (sys$getuai(0,0,&un_desc,&uai_list,0,0,0) != SS$_NORMAL) {sprintf(msgbuf,"No such user (%s).\n",user_arg); net_msg(msgbuf); return;} owner.string[owner.len] = 0; strcat(owner.string,")"); convert_time((char *)&lastlogin, (char *) &ll_string); open_mailfile("VMSMAIL_PROFILE","SYS$SYSTEM:.DATA"); mail_count = mail_check(user_arg); close_mailfile(); sprintf(msgbuf, " Username: %-12.12s (%-31.31s New mail: %d\nLast login: %s\n", user_arg,&owner.string,mail_count,&ll_string); net_msg(msgbuf); } convert_time(char *bintim, char *asctim) { short int str_len; struct descriptor ast_desc; ast_desc.len = 80; ast_desc.adr = asctim; sys$asctim(&str_len,&ast_desc,bintim,0); asctim[str_len] = 0; } /******************************* * Mail profile access routine * *******************************/ #include struct FAB rmsfab; struct RAB rmsrab; struct XABKEY key0; #ifdef __DECC #pragma __member_alignment save #pragma __nomember_alignment #endif struct mailrec {char filler[35]; short int mail_count;} mail_rec; #ifdef __DECC #pragma __member_alignment restore #endif long int fab_status,rab_status; /* * Open the indexed file; initialize XAB, FAB, and RAB data structures */ open_mailfile(char *filename, char *defname) { key0 = cc$rms_xabkey; /* Key 0: username */ key0.xab$b_ref = 0; key0.xab$b_dtp = XAB$C_STG; key0.xab$w_pos0 = 0; key0.xab$b_siz0 = 31; key0.xab$l_nxt = 0; rmsfab = cc$rms_fab; /* File Access Block */ rmsfab.fab$b_fns = strlen(filename); rmsfab.fab$l_fna = filename; if (defname) { rmsfab.fab$b_dns = strlen(defname); rmsfab.fab$l_dna = defname; } rmsfab.fab$w_mrs = 2048; rmsfab.fab$b_fac = FAB$M_GET; rmsfab.fab$b_shr = FAB$M_SHRDEL | FAB$M_SHRGET | FAB$M_SHRPUT | FAB$M_SHRUPD; rmsfab.fab$l_xab = (char *) &key0; rmsrab = cc$rms_rab; /* Record Access Block */ rmsrab.rab$l_fab = &rmsfab; rmsrab.rab$l_rop = RAB$M_NLK | RAB$M_UIF; rmsrab.rab$w_usz = sizeof(struct mailrec); fab_status = sys$open(&rmsfab); if (fab_status == RMS$_NORMAL) rab_status = sys$connect(&rmsrab); if (fab_status == RMS$_NORMAL) return(1); else return(0); } /* * Get a record by a specified key */ mail_check(char *username) { rmsrab.rab$b_krf = 0; rmsrab.rab$l_kbf = username; rmsrab.rab$b_ksz = strlen(username); rmsrab.rab$b_rac = RAB$C_KEY; rmsrab.rab$l_rop = RAB$M_NLK | RAB$M_UIF; rmsrab.rab$l_ubf = (char *) &mail_rec; rab_status = sys$get(&rmsrab); if (rab_status == RMS$_RTB) rab_status = SS$_NORMAL; if (!(rab_status & 1)) return (0); return(mail_rec.mail_count); } /* * Close the mailfile */ close_mailfile(void) { fab_status = sys$close(&rmsfab); if (fab_status == RMS$_NORMAL) return(1); else return(0); } upper_case(char *str_ptr) { while (*str_ptr != 0) {if ((*str_ptr >= 'a') && (*str_ptr <= 'z')) *str_ptr &= 0xDF; str_ptr++;} }