From: jamese@beast.dtsw.army.mil Sent: Wednesday, August 29, 2001 11:19 AM To: Info-VAX@Mvb.Saic.Com Subject: Re: SYS UAF / Password Expiration "W. Sherman" wrote in <9miooo$1e$1@ra.nrl.navy.mil> on Wed, 29 Aug 2001 09:02:38 -0400: > Is there some way, either via lexical functions in command script, or > something already established in vms, to notify users via e-mail that their > password is about to expire? > > The reason I ask is that I have numerous users that only use the server for > mail (pop and imap). When their password expires they aren't able to > retrieve mail. These users almost NEVER connect to the server for any other > reasons, so the passwords expire without them even knowing it.....it makes > for an administrative nightmare. > > Any help in this matter is appreciated. Attached is password_days_left.c. We run it in a nightly batch job and send mail to users that have passwords that are about to expire. Ed James ed.james@telecomsys.com TeleCommunications Systems, Inc. voice 410-295-1919 2024 West Street, Suite 300 800-810-0827 x1919 Annapolis, MD 21401-3556 fax 410-280-1094 /* password-days-left.c show days left until password expires Parts of this program based on dormant.c by Darrell Blair Ed James ed.james@telecomsys.com TeleCommunications Systems, Inc. voice 410-295-1919 2024 West Street, Suite 300 800-810-0827 x1919 Annapolis, MD 21401-3556 fax 410-280-1094 */ char version[15] = "03200006090940"; #include ssdef #include stdlib #include stdio #include string #include descrip #include uaidef #include starlet #include lib$routines #include str$routines #define check(stat) if ((stat&1) != 1) lib$stop(stat) #define test(stat) if(((stat)&1) != 1) {\ if(exit_with_count_only) exit((stat)|0x90000000);\ else lib$stop((stat));} #define ERRMSG fprintf(stderr, typedef int BOOL; typedef struct itmlst { short buffer_length, item_code; long *buffer_address, *return_length_address; } ITMLST; typedef unsigned long LONG; typedef struct { LONG long1, long2; } TIME; /*===========================================================================*/ void show_command_line_options( void) { ERRMSG "PASSWORD-DAYS-LEFT V(%s) syntax:\n", version); ERRMSG "password_days_left [parameters]\n"); ERRMSG " -h Display this help\n"); ERRMSG " -u name User account name. REQUIRED\n"); ERRMSG " -w nnn Warn if password expires within nnn days.\n"); ERRMSG " -x Exit with status only.\n"); ERRMSG "\n"); ERRMSG " The program always returns status of the form: %%X10ddddds\n"); ERRMSG " where: 10 inhibit message\n"); ERRMSG " ddddd is days until expiration\n"); ERRMSG " s severity: 1 normal exit, 0 warning - \n"); ERRMSG " password will expire within warn days (see -w).\n"); return; } /* end of show_command_line_options */ /*===========================================================================*/ main( int argc, char *argv[]) { static TIME last_pwd_change, pwd_lifetime, pwd_expires; static long uaiflags; int ii, days_in_era, days_to_pwd_change, context = (-1); int scan_rc, lifetime_days, day_of_week, status, warn_days = 7; int expire_days, exit_status; BOOL param_error = FALSE, display_help = FALSE; BOOL return_code_only = FALSE; BOOL exit_with_count_only = FALSE; /* The program always exits with a status code of the form: 0x10ddddds where: 10 VMS inhibit message flag ddddd Days until password expires s Severity: 1 normal completion 0 warning - password expires in less than warn days If the password expires in less than warn days, the expiration date is printed in a message. If exit_with_count_only is set to TRUE, no message is printed. System status return codes are returned as negative numbers. The next higher level (usually a command file) then must decide what to do. The high bit ('80000000'x) used to fake a negative number is reserved for DEC use but not used as of 930714. */ struct dsc$descriptor_s user_desc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0 }, time_string_desc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0 }; short timlen; char user[255]; char time_string[] = "dd-mmm-yyyy hh:mm:ss.cc DISUSER"; char days[7][10] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" }; ITMLST uai_itmlst[4] = { { sizeof( TIME), UAI$_PWD_DATE, (long *) &last_pwd_change, 0 }, { sizeof( TIME), UAI$_PWD_LIFETIME, (long *) &pwd_lifetime, 0 }, { sizeof( uaiflags), UAI$_FLAGS, &uaiflags, 0 }, { 0, 0, 0, 0 }}; for( ii=1; ii < argc; ii++) { if( argv[ii][0] == '-') { switch( argv[ii][1]) { case 'h' : display_help = TRUE; break; case 'u' : if( (ii + 1) >= argc) { ERRMSG "Argument missing %s\n", argv[ii]); param_error = TRUE; } else { user[sizeof( user) - 1] == '\0'; strncpy( user, argv[ii+1], sizeof( user) - 1); ii++; } break; case 'w' : if( (ii + 1) >= argc) { ERRMSG "Argument missing %s\n", argv[ii]); param_error = TRUE; } else { scan_rc = sscanf( argv[ii+1], "%d", &warn_days); if( scan_rc != 1) { ERRMSG "Argument missing %s\n", argv[ii]); param_error = TRUE; } ii++; } break; case 'x' : exit_with_count_only = TRUE; break; default : ERRMSG "Unknown argument %s\n", argv[ii]); param_error = TRUE; break; } } else { ERRMSG "Unknown argument %s\n", argv[ii]); param_error = TRUE; } } if( display_help || param_error) {; show_command_line_options(); exit( param_error == TRUE ? EXIT_FAILURE : EXIT_SUCCESS); } if( user[0] == '\0') { ERRMSG "Username parameter required\n"); show_command_line_options(); exit( EXIT_FAILURE); } user_desc.dsc$w_length = strlen( user); user_desc.dsc$a_pointer = user; status = str$upcase( &user_desc, &user_desc); test( status); time_string_desc.dsc$w_length = sizeof( time_string) - 1; time_string_desc.dsc$a_pointer = time_string; status = lib$day( &days_in_era, 0); test( status); status = sys$getuai( 0, &context, &user_desc, &uai_itmlst, 0, 0, 0); test( status); status = lib$day( &days_to_pwd_change, &last_pwd_change); test( status); if( pwd_lifetime.long1 == 0 && pwd_lifetime.long2 == 0) { exit( 0x10fffff1); /* fffff = 1048575 days, i.e., does not expire. */ } status = lib$day( &lifetime_days, &pwd_lifetime); test( status); status = lib$add_times( &last_pwd_change, &pwd_lifetime, &pwd_expires); test( status); status = sys$asctim( &timlen, &time_string_desc, &pwd_expires); test( status); time_string[timlen] = '\0'; status = lib$day_of_week( &pwd_expires, &day_of_week); test( status); expire_days = (days_to_pwd_change + abs( lifetime_days)) - days_in_era; if( uaiflags & UAI$M_DISACNT) { strcat( time_string, "DISUSER"); } exit_status = ((expire_days & 0x000fffff) << 4) | 0x10000001; if( expire_days <= warn_days) { exit_status = exit_status & 0xfffffff0; /* make severity 0 (warning) */ if( ! exit_with_count_only) { printf( "Password for %s expires in %d days on %s %s\n", user, expire_days, days[day_of_week-1], time_string); } } exit( exit_status); }