Imported Upstream version 1.8.2
[debian/sudo] / common / aix.c
1 /*
2  * Copyright (c) 2008, 2010-2011 Todd C. Miller <Todd.Miller@courtesan.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <config.h>
18
19 #include <sys/types.h>
20 #include <sys/resource.h>
21
22 #include <stdio.h>
23 #ifdef STDC_HEADERS
24 # include <stdlib.h>
25 # include <stddef.h>
26 #else
27 # ifdef HAVE_STDLIB_H
28 #  include <stdlib.h>
29 # endif
30 #endif /* STDC_HEADERS */
31 #include <usersec.h>
32 #include <uinfo.h>
33
34 #include "missing.h"
35 #include "alloc.h"
36 #include "error.h"
37
38 #define DEFAULT_TEXT_DOMAIN     "sudo"
39 #include "gettext.h"
40
41 #ifdef HAVE_GETUSERATTR
42
43 #ifndef HAVE_SETRLIMIT64
44 # define setrlimit64(a, b) setrlimit(a, b)
45 # define rlimit64 rlimit
46 # define rlim64_t rlim_t
47 # define RLIM64_INFINITY RLIM_INFINITY
48 #endif /* HAVE_SETRLIMIT64 */
49
50 #ifndef RLIM_SAVED_MAX
51 # define RLIM_SAVED_MAX RLIM64_INFINITY
52 #endif
53
54 struct aix_limit {
55     int resource;
56     char *soft;
57     char *hard;
58     int factor;
59 };
60
61 static struct aix_limit aix_limits[] = {
62     { RLIMIT_FSIZE, S_UFSIZE, S_UFSIZE_HARD, 512 },
63     { RLIMIT_CPU, S_UCPU, S_UCPU_HARD, 1 },
64     { RLIMIT_DATA, S_UDATA, S_UDATA_HARD, 512 },
65     { RLIMIT_STACK, S_USTACK, S_USTACK_HARD, 512 },
66     { RLIMIT_RSS, S_URSS, S_URSS_HARD, 512 },
67     { RLIMIT_CORE, S_UCORE, S_UCORE_HARD, 512 },
68     { RLIMIT_NOFILE, S_UNOFILE, S_UNOFILE_HARD, 1 }
69 };
70
71 static int
72 aix_getlimit(char *user, char *lim, rlim64_t *valp)
73 {
74     int val;
75
76     if (getuserattr(user, lim, &val, SEC_INT) != 0)
77         return -1;
78     *valp = val;
79     return 0;
80 }
81
82 static void
83 aix_setlimits(char *user)
84 {
85     struct rlimit64 rlim;
86     rlim64_t val;
87     int n;
88
89     if (setuserdb(S_READ) != 0)
90         error(1, "unable to open userdb");
91
92     /*
93      * For each resource limit, get the soft/hard values for the user
94      * and set those values via setrlimit64().  Must be run as euid 0.
95      */
96     for (n = 0; n < sizeof(aix_limits) / sizeof(aix_limits[0]); n++) {
97         /*
98          * We have two strategies, depending on whether or not the
99          * hard limit has been defined.
100          */
101         if (aix_getlimit(user, aix_limits[n].hard, &val) == 0) {
102             rlim.rlim_max = val == -1 ? RLIM64_INFINITY : val * aix_limits[n].factor;
103             if (aix_getlimit(user, aix_limits[n].soft, &val) == 0)
104                 rlim.rlim_cur = val == -1 ? RLIM64_INFINITY : val * aix_limits[n].factor;
105             else
106                 rlim.rlim_cur = rlim.rlim_max;  /* soft not specd, use hard */
107         } else {
108             /* No hard limit set, try soft limit. */
109             if (aix_getlimit(user, aix_limits[n].soft, &val) == 0)
110                 rlim.rlim_cur = val == -1 ? RLIM64_INFINITY : val * aix_limits[n].factor;
111
112             /* Set hard limit per AIX /etc/security/limits documentation. */
113             switch (aix_limits[n].resource) {
114                 case RLIMIT_CPU:
115                 case RLIMIT_FSIZE:
116                     rlim.rlim_max = rlim.rlim_cur;
117                     break;
118                 case RLIMIT_STACK:
119                     rlim.rlim_max = RLIM_SAVED_MAX;
120                     break;
121                 default:
122                     rlim.rlim_max = RLIM64_INFINITY;
123                     break;
124             }
125         }
126         (void)setrlimit64(aix_limits[n].resource, &rlim);
127     }
128     enduserdb();
129 }
130
131 #ifdef HAVE_SETAUTHDB
132 /*
133  * Look up administrative domain for user (SYSTEM in /etc/security/user) and
134  * set it as the default for the process.  This ensures that password and
135  * group lookups are made against the correct source (files, NIS, LDAP, etc).
136  */
137 void
138 aix_setauthdb(char *user)
139 {
140     char *registry;
141
142     if (user != NULL) {
143         if (setuserdb(S_READ) != 0)
144             error(1, _("unable to open userdb"));
145         if (getuserattr(user, S_REGISTRY, &registry, SEC_CHAR) == 0) {
146             if (setauthdb(registry, NULL) != 0)
147                 error(1, _("unable to switch to registry \"%s\" for %s"),
148                     registry, user);
149         }
150         enduserdb();
151     }
152 }
153
154 /*
155  * Restore the saved administrative domain, if any.
156  */
157 void
158 aix_restoreauthdb(void)
159 {
160     if (setauthdb(NULL, NULL) != 0)
161         error(1, _("unable to restore registry"));
162 }
163 #endif
164
165 void
166 aix_prep_user(char *user, const char *tty)
167 {
168     char *info;
169     int len;
170
171     /* set usrinfo, like login(1) does */
172     len = easprintf(&info, "NAME=%s%cLOGIN=%s%cLOGNAME=%s%cTTY=%s%c",
173         user, '\0', user, '\0', user, '\0', tty ? tty : "", '\0');
174     (void)usrinfo(SETUINFO, info, len);
175     efree(info);
176
177 #ifdef HAVE_SETAUTHDB
178     /* set administrative domain */
179     aix_setauthdb(user);
180 #endif
181
182     /* set resource limits */
183     aix_setlimits(user);
184 }
185 #endif /* HAVE_GETUSERATTR */