root/op/1.27/main.c

Revision 220, 27.7 kB (checked in by athomas, 4 years ago)

Added nolog

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