root/op/1.25/main.c

Revision 214, 26.3 kB (checked in by athomas, 5 years ago)

Branched version 1.25.

Line 
1 /* +-------------------------------------------------------------------+ */
2 /* | Copyright 1991, David Koblas.                                     | */
3 /* |   Permission to use, copy, modify, and distribute this software   | */
4 /* |   and its documentation for any purpose and without fee is hereby | */
5 /* |   granted, provided that the above copyright notice appear in all | */
6 /* |   copies and that both that copyright notice and this permission  | */
7 /* |   notice appear in supporting documentation.  This software is    | */
8 /* |   provided "as is" without express or implied warranty.           | */
9 /* +-------------------------------------------------------------------+ */
10
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <sys/wait.h>
14 #include <errno.h>
15 #include <sys/time.h>
16 #include <netdb.h>
17 #include <time.h>
18 #include <signal.h>
19 #include <stdio.h>
20 #include <stdarg.h>
21 #include <syslog.h>
22 #include <pwd.h>
23 #include <grp.h>
24 #include <stdlib.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include "defs.h"
28 #include "regexp.h"
29
30 #ifdef sun
31 #  if defined(__SVR4) || defined(__svr4__)
32 #    define SOLARIS
33 #  endif
34 #endif
35
36 #if defined(USE_SHADOW) && defined(USE_PAM)
37 #error USE_SHADOW and USE_PAM are mutually exclusive
38 #endif
39
40 #ifdef USE_SHADOW
41 #include <shadow.h>
42 #endif
43
44 #ifdef USE_PAM
45 #include <security/pam_appl.h>
46 #endif
47
48 #ifdef SECURID
49 #include "sdi_athd.h"
50 #include "sdconf.h"
51 union config_record configure;
52 #endif
53
54 #ifndef LOG_AUTH
55 /*
56 **  Pmax's don't have LOG_AUTH
57 */
58 #define LOG_AUTH LOG_WARNING
59 #endif
60
61 #define LOG_PRINT       (1UL << 31)
62
63 #define MAXARG  1024
64 #define MAXENV  MAXARG
65
66 #ifndef _AIX
67 extern char     *strchr();
68 #endif
69 extern char     *savestr();
70 extern char     *getpass(), *crypt();
71
72 char    *format_cmd(int argc, char **argv, char *retbuf, int buflen);
73 char    *GetCode();
74 cmd_t   *Find();
75 int Verify(cmd_t *cmd, int num, int argc, char **argv);
76 cmd_t   *Find(char *name);
77 int Go(cmd_t *cmd, int num, int argc, char **argv);
78 cmd_t   *First = NULL;
79 var_t   *Variables = NULL;
80 struct passwd *realuser = NULL;
81 int gargc = -1;
82 char **gargv = NULL;
83 sigset_t sig_mask, old_sig_mask;
84
85 void Usage()
86 {
87         fatal(0, "Usage: %s mnemonic [args]\n       %s -V -H [-u username] mnemonic",
88                         gargv[0], gargv[0]);
89 }
90
91 int main(argc, argv)
92 int     argc;
93 char    **argv;
94 {
95         int             num, argStart = 1;
96         char            user[MAXSTRLEN];
97         cmd_t           *cmd, *def, *new;
98         struct passwd   *pw;
99         int             hflag = 0;
100         char            *uptr = NULL;
101         char            cmd_s[MAXSTRLEN];
102         char            *pcmd_s;
103
104         sigemptyset(&sig_mask);
105         sigaddset(&sig_mask, SIGINT);
106         sigaddset(&sig_mask, SIGQUIT);
107         sigaddset(&sig_mask, SIGTERM);
108
109         if (sigprocmask(SIG_BLOCK, &sig_mask, &old_sig_mask))
110                 fatal(1, "Could not set signal mask");
111
112         gargv = argv;
113         gargc = argc;
114         realuser = getpwuid(getuid());
115
116         while (1) {
117                 if (argStart >= argc)
118                         break;
119
120                 if (strcmp("-V", argv[argStart]) == 0) {
121                         printf("%s\n", VERSION);
122                         return 0;
123                 } else if (strcmp("-H", argv[argStart]) == 0) {
124                         hflag++;
125                         argStart++;
126                 } else if (strcmp("-u", argv[argStart]) == 0) {
127                         if (strlen(argv[argStart]) == 2) {
128                                 if (argStart+1 >= argc)
129                                         Usage();
130                                 argStart++;
131                                 uptr = argv[argStart];
132                         }
133                         argStart++;
134                 } else if (strcmp("-uH", argv[argStart]) == 0) {
135                         hflag++;
136                         if (strlen(argv[argStart]) == 3) {
137                                 if (argStart+1 >= argc)
138                                         Usage();
139                                 argStart++;
140                                 uptr = argv[argStart];
141                         }
142                         argStart++;
143                 } else if (strcmp("-Hu", argv[argStart]) == 0) {
144                         hflag++;
145                         if (strlen(argv[argStart]) == 3) {
146                                 if (argStart+1 >= argc)
147                                         Usage();
148                                 argStart++;
149                                 uptr = argv[argStart];
150                         }
151                         argStart++;
152                 } else {
153                         break;
154                 }
155         }
156
157 #if defined (bsdi) || defined (SOLARIS) || defined (__linux__)
158         openlog("op", LOG_PID | LOG_CONS, LOG_AUTH);
159 #else
160         if (openlog("op", LOG_PID | LOG_CONS, LOG_AUTH) < 0)
161                 fatal(0, "openlog failed");
162 #endif
163         ReadFile( OP_ACCESS );
164
165         if (hflag) {
166                 if (uptr != NULL) {
167                         if (getuid() != 0)
168                                 fatal(1, "Permission denied for -u option");
169                 }
170         }
171         if (uptr != NULL)
172                 Usage();
173
174         if (argStart >= argc)
175                 Usage();
176
177         def = Find("DEFAULT");
178         cmd = Find(argv[argStart]);
179
180         if (cmd == NULL)
181                 fatal(1, "No such command %s", argv[1]);
182
183         argc -= argStart;
184         argv += argStart;
185
186         new = Build(def, cmd);
187         num = CountArgs(new);
188
189         if ((num < 0) && ((argc-1) < -num))
190                 fatal(1, "Improper number of arguments");
191         if ((num > 0) && ((argc-1) != num))
192                 fatal(1, "Improper number of arguments");
193         if (num <0)
194                 num = -num;
195
196         if ((pw = getpwuid(getuid())) == NULL)
197                 exit(1);
198         realuser = getpwuid(getuid());
199         strncpy(user, pw->pw_name, MAXSTRLEN);
200         pcmd_s = format_cmd(argc, argv, cmd_s, MAXSTRLEN);
201         if (Verify(new, num, argc, argv) < 0)
202                 fatal(0, "Permission denied by op");
203
204         return Go(new, num, argc, argv);
205 }
206
207 cmd_t   *Find(name)
208 char    *name;
209 {
210         cmd_t   *cmd;
211
212         for (cmd = First; cmd != NULL; cmd = cmd ->next) {
213                 if (strcmp(cmd->name, name) == 0)
214                         break;
215         }
216
217         return cmd;
218 }
219
220 char    *FindOpt(cmd, str)
221 cmd_t   *cmd;
222 char    *str;
223 {
224         static char     nul[2] = "";
225         int             i;
226         char            *cp;
227
228         for (i = 0; i < cmd->nopts; i++) {
229                 if ((cp = strchr(cmd->opts[i], '=')) == NULL) {
230                         if (strcmp(cmd->opts[i], str) == 0)
231                                 return nul;
232                 } else {
233                         int     l = cp - cmd->opts[i];
234                         if (strncmp(cmd->opts[i], str, l) == 0)
235                                 return cp+1;
236                 }
237         }
238
239         return NULL;
240 }
241
242 char    *GetField(cp, str, len)
243 char    *cp, *str;
244 int len;
245 {
246 char *end = str + len - 2;
247
248         if (*cp == '\0')
249                 return NULL;
250
251         while ((*cp != '\0') && (*cp != ',')) {
252                 if (*cp == '\\')
253                         if (*(cp+1) == ',') {
254                                 *str++ = ',';
255                                 cp++;
256                         } else
257                                 *str++ = '\\';
258                 else
259                         *str++ = *cp;
260                 cp++;
261                 /* string exceeded target buffer length */
262                 if (str >= end)
263                         return NULL;
264         }
265
266         *str = '\0';
267
268         return (*cp == '\0') ? cp : (cp+1);
269 }
270
271 #ifdef USE_PAM
272 int pam_conversation(int num_msg, const struct pam_message **msg, struct pam_response **response, void *appdata_ptr) {
273 int i;
274 const struct pam_message *pm;
275 struct pam_response *pr;
276 char *pass;
277
278         if ((*response = malloc(sizeof(struct pam_response) * num_msg)) == NULL)
279                 return PAM_CONV_ERR;
280         memset(*response, 0, num_msg * sizeof(struct pam_response));
281
282         for (i = 0, pm = *msg, pr = *response; i < num_msg; ++i, ++pm, ++pr) {
283                 switch (pm->msg_style) {
284                         case PAM_PROMPT_ECHO_ON :
285                                 if (!(pass = malloc(512))) return PAM_CONV_ERR;
286                                 puts(pm->msg);
287                                 fgets(pass, 512, stdin);
288                                 pr->resp = pass;
289                         break;
290                         case PAM_PROMPT_ECHO_OFF :
291                                 if ((pass = getpass(pm->msg)) == NULL) {
292                                         for (pr = *response, i = 0; i < num_msg; ++i, ++pr)
293                                                 if (pr->resp) {
294                                                         memset(pr->resp, 0, strlen(pr->resp));
295                                                         free(pr->resp);
296                                                         pr->resp = NULL;
297                                                 }
298                                         memset(*response, 0, num_msg * sizeof(struct pam_response));
299                                         free(*response);
300                                         *response = NULL;
301                                         return PAM_CONV_ERR;
302                                 }
303                                 pr->resp = strdup(pass);
304                         break;
305                         case PAM_TEXT_INFO :
306                                 if (pm->msg)
307                                         puts(pm->msg);
308                         break;
309                         case PAM_ERROR_MSG :
310                                 if (pm->msg) {
311                                         fputs(pm->msg, stderr);
312                                         fputc('\n', stderr);
313                                 }
314                         break;
315                         default :
316                                 for (pr = *response, i = 0; i < num_msg; ++i, ++pr)
317                                         if (pr->resp) {
318                                                 memset(pr->resp, 0, strlen(pr->resp));
319                                                 free(pr->resp);
320                                                 pr->resp = NULL;
321                                         }
322                                 memset(*response, 0, num_msg * sizeof(struct pam_response));
323                                 free(*response);
324                                 *response = NULL;
325                                 return PAM_CONV_ERR;
326                         break;
327                 }
328         }
329         return PAM_SUCCESS;
330 }
331
332 #endif
333
334 int Verify(cmd, num, argc, argv)
335 cmd_t   *cmd;
336 int     argc;
337 int     num;
338 char    **argv;
339 {
340 int             gr_fail = 1, uid_fail = 1, netgr_fail = 1;
341 int             i, j, val;
342 char            *np, *cp, str[MAXSTRLEN], buf[MAXSTRLEN], hostname[HOST_NAME_MAX];
343 regexp          *reg1 = NULL;
344 regexp          *reg2 = NULL;
345 struct passwd   *pw;
346 #ifdef USE_SHADOW
347 struct spwd *spw;
348 #endif
349 #ifdef USE_PAM
350 struct pam_conv pamconv = { pam_conversation, NULL };
351 pam_handle_t *pam;
352 #endif
353 struct group    *gr;
354 #ifdef SECURID
355 struct          SD_CLIENT sd_dat, *sd;
356 int             k;
357 char            input[64],*p;
358 #endif
359
360         if ((pw = getpwuid(getuid())) == NULL) return -1;
361
362 #ifdef SECURID
363         if ((cp=FindOpt(cmd, "securid")) != NULL) {
364                 memset(&sd_dat, 0, sizeof(sd_dat));   /* clear sd_auth struct */
365                 sd = &sd_dat;
366                 creadcfg();             /*  accesses sdconf.rec  */
367                 if (sd_init(sd)){
368                         return logger(LOG_WARNING | LOG_PRINT, "Cannot contact ACE server");
369                 }
370                 if (sd_auth(sd)) return -1;
371         }
372 #else
373         if ((cp=FindOpt(cmd, "securid")) != NULL) {
374                 return logger(LOG_ERR | LOG_PRINT, "SecureID not supported by op. Access denied");
375         }
376 #endif 
377
378         if ((cp=FindOpt(cmd, "password")) != NULL) {
379 #ifdef USE_PAM
380                 if ((cp = GetField(cp, str, MAXSTRLEN)) != NULL) {
381                         if ((np = getpass("Password:")) == NULL)
382                                 return logger(LOG_ERR, "Could not get user password");
383
384                         if (strcmp(crypt(np, str), str) != 0)
385                                 return logger(LOG_ERR, "Incorrect direct password");
386                 } else {
387                 int resp;
388
389                         resp = pam_start("op", pw->pw_name, &pamconv, &pam);
390                         if (resp == PAM_SUCCESS)
391                                 resp = pam_authenticate(pam, PAM_SILENT);
392                         if (resp == PAM_SUCCESS)
393                                 resp = pam_acct_mgmt(pam, 0);
394                         if (resp != PAM_SUCCESS) {
395                                 return logger(LOG_ERR, "pam_authticate: %s", pam_strerror(pam, resp));
396                         }
397                         pam_end(pam, resp);
398                 }
399 #else
400                 if ((np = getpass("Password:")) == NULL)
401                         return logger(LOG_ERR, "Could not get user password");
402
403                 if ((cp = GetField(cp, str, MAXSTRLEN)) != NULL) {
404                         if (strcmp(crypt(np, str), str) != 0)
405                                 return logger(LOG_ERR, "Incorrect direct password");
406                 } else {
407 #ifdef USE_SHADOW
408                         if (strcmp(pw->pw_passwd,"x")==0){ /* Shadow passwords */
409                                 if ((spw = getspnam(pw->pw_name)) == NULL)
410                                         return logger(LOG_ERR, "No shadow entry for '%s'", pw->pw_name);
411                                 pw->pw_passwd=spw->sp_pwdp;
412                         }
413 #endif
414
415                         if (!cp && strcmp(crypt(np, pw->pw_passwd), pw->pw_passwd) != 0)
416                                 return logger(LOG_ERR, "Invalid user password");
417                 }
418 #endif
419         }
420
421         if (gethostname(hostname, HOST_NAME_MAX) == -1)
422                 return logger(LOG_ERR, "Could not get hostname");
423
424         if ((pw = getpwuid(getuid())) == NULL)
425                 return logger(LOG_ERR, "Could not get uid of current effective uid");
426
427         if ((cp = FindOpt(cmd, "groups")) != NULL) {
428         char grouphost[MAXSTRLEN + HOST_NAME_MAX],
429                 regstr[MAXSTRLEN];
430
431                 for (cp = GetField(cp, str, MAXSTRLEN - 5); cp != NULL; cp = GetField(cp, str, MAXSTRLEN - 5)) {
432                         strcpy(regstr, "^(");
433                         strcat(regstr, str);
434                         strcat(regstr, ")$");
435
436                         if ((reg1 = regcomp(regstr)) == NULL)
437                                 return logger(LOG_ERR, "Invalid regex '%s'", regstr);
438
439                         if ((gr = getgrgid(pw->pw_gid)) != NULL) {
440                                 strcpy(grouphost, gr->gr_name);
441                                 strcat(grouphost, "@");
442                                 strcat(grouphost, hostname);
443
444                                 if (regexec(reg1,gr->gr_name) == 1 || regexec(reg1, grouphost)) {
445                                         gr_fail = 0;
446                                         break;
447                                 }
448                         }
449
450                         setgrent();
451                         while ((gr = getgrent()) != NULL) {
452                                 i = 0;
453                                 while (gr->gr_mem[i] != NULL) {
454                                         if (strcmp(gr->gr_mem[i], pw->pw_name)==0) break;
455                                         i++;
456                                 }
457
458                                 if (gr->gr_mem[i] != NULL) {
459                                         strcpy(grouphost, gr->gr_name);
460                                         strcat(grouphost, "@");
461                                         strcat(grouphost, hostname);
462                                         if (regexec(reg1, gr->gr_name) == 1 || regexec(reg1, grouphost)) {
463                                                 gr_fail = 0;
464                                                 break;
465                                         }
466                                 }
467                         }
468                 }
469         }
470         if(reg1 != NULL){
471                 free(reg1);
472                 reg1=NULL;
473         }
474
475         if (gr_fail && ((cp = FindOpt(cmd, "users")) != NULL)) {
476         char currenttime[13], userhost[MAXSTRLEN + HOST_NAME_MAX],
477                 regstr[MAXSTRLEN];
478         time_t now = time(NULL);
479                
480                 strftime(currenttime, 13, "%Y%m%d%H%M", localtime(&now));
481
482                 for (cp=GetField(cp, str, MAXSTRLEN - 5); cp!=NULL; cp=GetField(cp, str, MAXSTRLEN - 5)) {
483                 char expiretime[13], *expirestart = strchr(str, '/');
484
485                         if (expirestart) *expirestart = 0;
486
487                         strcpy(regstr, "^(");
488                         strcat(regstr, str);
489                         strcat(regstr, ")$");
490
491                         strcpy(userhost, pw->pw_name);
492                         strcat(userhost, "@");
493                         strcat(userhost, hostname);
494
495                         if ((reg1=regcomp(regstr)) == NULL)
496                                 return logger(LOG_ERR, "Invalid regex '%s'", regstr);
497
498                         if (regexec(reg1,pw->pw_name) == 1 || regexec(reg1, userhost) == 1) {
499           &nb