]>
Commit | Line | Data |
---|---|---|
7283d000 | 1 | /* |
2 | * Copyright 1988 by the Massachusetts Institute of Technology. For copying | |
5eaef520 | 3 | * and distribution information, see the file "mit-copyright.h". |
7283d000 | 4 | * |
5 | * $Source$ | |
6 | * $Header$ | |
7 | * $Author$ | |
8 | * | |
9 | */ | |
10 | ||
11 | #ifndef lint | |
12 | static char *rcsid_chfn_c = "$Header$"; | |
ca1102ea | 13 | #endif |
7283d000 | 14 | |
15 | /* | |
8defc06b | 16 | * Talk to the MOIRA database to change a person's GECOS information. |
5eaef520 | 17 | * |
18 | * chfn with no modifiers changes the information of the user who is | |
7283d000 | 19 | * running the program. |
5eaef520 | 20 | * |
7283d000 | 21 | * If a commandline argument is given, it is taken to be the username |
22 | * of the user whose information is to be changed. | |
23 | * | |
24 | */ | |
25 | ||
26 | #define FALSE 0 | |
27 | #define TRUE 1 | |
28 | ||
29 | #include <sys/types.h> | |
30 | #include <stdio.h> | |
f071d8a7 | 31 | #include <string.h> |
7283d000 | 32 | #include <sys/file.h> |
33 | #include <krb.h> | |
34 | #include <ctype.h> | |
35 | #include <errno.h> | |
36 | ||
8defc06b | 37 | /* MOIRA includes */ |
38 | #include <moira.h> | |
39 | #include <moira_site.h> | |
7283d000 | 40 | #include "mit-copyright.h" |
41 | ||
42 | char *whoami; | |
43 | ||
7283d000 | 44 | struct finger_info { |
5eaef520 | 45 | char *fullname; |
46 | char *nickname; | |
47 | char *home_address; | |
48 | char *home_phone; | |
49 | char *office_address; | |
50 | char *office_phone; | |
51 | char *mit_department; | |
52 | char *mit_year; | |
7283d000 | 53 | }; |
54 | ||
5eaef520 | 55 | int main(int argc, char *argv[]) |
7283d000 | 56 | { |
5eaef520 | 57 | char pname[ANAME_SZ]; |
58 | char *uname = pname; | |
59 | int k_errno; | |
7283d000 | 60 | |
5eaef520 | 61 | initialize_krb_error_table(); |
ca1102ea | 62 | |
5eaef520 | 63 | if ((whoami = strrchr(argv[0], '/')) == NULL) |
64 | whoami = argv[0]; | |
65 | else | |
66 | whoami++; | |
7283d000 | 67 | |
5eaef520 | 68 | if (argc > 2) |
69 | usage(); | |
70 | ||
71 | if (argc == 2) | |
72 | uname = argv[1]; | |
73 | else | |
7283d000 | 74 | { |
5eaef520 | 75 | /* Do it right; get name from kerberos ticket file rather than |
76 | from passord file. */ | |
77 | ||
78 | if ((k_errno = tf_init(TKT_FILE, R_TKT_FIL))) | |
79 | { | |
80 | com_err(whoami, k_errno, "reading ticket file"); | |
81 | exit(1); | |
7283d000 | 82 | } |
5eaef520 | 83 | |
84 | if (k_errno = tf_get_pname(pname)) | |
85 | { | |
86 | com_err(whoami, k_errno, "getting kerberos principal name"); | |
87 | exit(1); | |
7283d000 | 88 | } |
89 | ||
5eaef520 | 90 | tf_close(); |
7283d000 | 91 | } |
5eaef520 | 92 | |
93 | exit(chfn(uname)); | |
7283d000 | 94 | } |
95 | ||
5eaef520 | 96 | /* This should be called rather than exit once connection to moira server |
97 | has been established. */ | |
98 | int leave(int status) | |
7283d000 | 99 | { |
5eaef520 | 100 | mr_disconnect(); |
101 | exit(status); | |
7283d000 | 102 | } |
103 | ||
5eaef520 | 104 | int scream(void) |
7283d000 | 105 | { |
5eaef520 | 106 | com_err(whoami, 0, "Unexpected return value from Moira -- programmer botch"); |
107 | leave(1); | |
7283d000 | 108 | } |
109 | ||
5eaef520 | 110 | int chfn(char *uname) |
7283d000 | 111 | { |
5eaef520 | 112 | int status; /* general purpose exit status */ |
113 | int q_argc; /* argc for mr_query */ | |
114 | char *q_argv[F_END]; /* argv for mr_query */ | |
115 | char *motd; /* for MR server status */ | |
116 | int i; | |
7283d000 | 117 | |
5eaef520 | 118 | int get_user_info(); |
119 | void get_new_info(); | |
7283d000 | 120 | |
5eaef520 | 121 | struct finger_info old_info; |
122 | struct finger_info new_info; | |
7283d000 | 123 | |
5eaef520 | 124 | /* Try each query. If we ever fail, print error message and exit. */ |
7283d000 | 125 | |
5eaef520 | 126 | status = mr_connect(NULL); |
127 | if (status) | |
128 | { | |
129 | com_err(whoami, status, "while connecting to Moira"); | |
130 | exit(1); | |
7283d000 | 131 | } |
132 | ||
5eaef520 | 133 | status = mr_motd(&motd); |
134 | if (status) | |
135 | { | |
136 | com_err(whoami, status, "unable to check server status"); | |
137 | leave(1); | |
262ca740 | 138 | } |
5eaef520 | 139 | if (motd) |
140 | { | |
141 | fprintf(stderr, "The Moira server is currently unavailable:\n%s\n", | |
142 | motd); | |
143 | leave(1); | |
262ca740 | 144 | } |
145 | ||
5eaef520 | 146 | status = mr_auth("chfn"); /* Don't use argv[0] - too easy to fake */ |
147 | if (status) | |
148 | { | |
149 | com_err(whoami, status, | |
150 | "while authenticating -- run \"kinit\" and try again."); | |
151 | leave(1); | |
7283d000 | 152 | } |
153 | ||
5eaef520 | 154 | /* First, do an access check. */ |
155 | ||
156 | q_argv[F_NAME] = uname; | |
157 | for (i = F_NAME + 1; i < F_MODTIME; i++) | |
158 | q_argv[i] = "junk"; | |
159 | q_argc = F_MODTIME; /* one more than the last updatable field */ | |
7283d000 | 160 | |
5eaef520 | 161 | if ((status = mr_access("update_finger_by_login", q_argc, q_argv))) |
162 | { | |
163 | com_err(whoami, status, "; finger\ninformation not changed."); | |
164 | leave(2); | |
7283d000 | 165 | } |
166 | ||
5eaef520 | 167 | printf("Changing finger information for %s.\n", uname); |
7283d000 | 168 | |
5eaef520 | 169 | /* Get information */ |
7283d000 | 170 | |
5eaef520 | 171 | q_argv[NAME] = uname; |
172 | q_argc = NAME + 1; | |
173 | if ((status = mr_query("get_finger_by_login", q_argc, q_argv, | |
174 | get_user_info, (char *) &old_info))) | |
7283d000 | 175 | { |
5eaef520 | 176 | com_err(whoami, status, "while getting user information."); |
177 | leave(2); | |
7283d000 | 178 | } |
179 | ||
5eaef520 | 180 | /* Get the new information from the user */ |
7283d000 | 181 | |
5eaef520 | 182 | get_new_info(&old_info, &new_info); |
7283d000 | 183 | |
5eaef520 | 184 | /* Do the update */ |
7283d000 | 185 | |
5eaef520 | 186 | printf("Changing finger information...\n"); |
7283d000 | 187 | |
5eaef520 | 188 | q_argv[F_NAME] = uname; |
189 | q_argv[F_FULLNAME] = new_info.fullname; | |
190 | q_argv[F_NICKNAME] = new_info.nickname; | |
191 | q_argv[F_HOME_ADDR] = new_info.home_address; | |
192 | q_argv[F_HOME_PHONE] = new_info.home_phone; | |
193 | q_argv[F_OFFICE_ADDR] = new_info.office_address; | |
194 | q_argv[F_OFFICE_PHONE] = new_info.office_phone; | |
195 | q_argv[F_MIT_DEPT] = new_info.mit_department; | |
196 | q_argv[F_MIT_AFFIL] = new_info.mit_year; | |
197 | q_argc = F_MODTIME; /* First non-update query argument */ | |
7283d000 | 198 | |
5eaef520 | 199 | if ((status = mr_query("update_finger_by_login", q_argc, q_argv, |
200 | scream, NULL))) | |
7283d000 | 201 | { |
5eaef520 | 202 | com_err(whoami, status, "while updating finger information."); |
203 | leave(1); | |
7283d000 | 204 | } |
205 | ||
5eaef520 | 206 | printf("Finger information updated succesfully.\n"); |
7283d000 | 207 | |
5eaef520 | 208 | return 0; |
7283d000 | 209 | } |
210 | ||
5eaef520 | 211 | int get_user_info(int argc, char *argv[], char *message) |
7283d000 | 212 | { |
5eaef520 | 213 | struct finger_info *old_info = (struct finger_info *) message; |
214 | ||
215 | if (argc != F_END) | |
216 | { | |
217 | fprintf(stderr, "Some internal error occurred; try again.\n"); | |
218 | leave(3); | |
7283d000 | 219 | } |
5eaef520 | 220 | |
221 | printf("Info last changed on %s by user %s with %s.\n", | |
222 | argv[F_MODTIME], argv[F_MODBY], argv[F_MODWITH]); | |
223 | ||
224 | old_info->fullname = strsave(argv[F_FULLNAME]); | |
225 | old_info->nickname = strsave(argv[F_NICKNAME]); | |
226 | old_info->home_address = strsave(argv[F_HOME_ADDR]); | |
227 | old_info->home_phone = strsave(argv[F_HOME_PHONE]); | |
228 | old_info->office_address = strsave(argv[F_OFFICE_ADDR]); | |
229 | old_info->office_phone = strsave(argv[F_OFFICE_PHONE]); | |
230 | old_info->mit_department = strsave(argv[F_MIT_DEPT]); | |
231 | old_info->mit_year = strsave(argv[F_MIT_AFFIL]); | |
232 | ||
233 | /* Only pay attention to the first match since login names are | |
234 | unique in the database. */ | |
235 | return MR_ABORT; | |
7283d000 | 236 | } |
237 | ||
5eaef520 | 238 | char *ask(char *question, char *def_val, int phone_num) |
7283d000 | 239 | { |
5eaef520 | 240 | static char buf[BUFSIZ]; |
241 | int ok = FALSE; | |
242 | char *result; | |
243 | int i; | |
244 | int dashes = FALSE; | |
245 | ||
7283d000 | 246 | #define BLANK "none" |
5eaef520 | 247 | |
248 | while (!ok) | |
7283d000 | 249 | { |
5eaef520 | 250 | ok = TRUE; |
251 | printf("%s [%s]: ", question, def_val); | |
252 | if (!fgets(buf, sizeof(buf), stdin)) | |
253 | leave(0); | |
254 | buf[strlen(buf) - 1] = '\0'; | |
255 | if (strlen(buf) == 0) | |
256 | result = def_val; | |
257 | else if (!strcasecmp(buf, BLANK)) | |
258 | result = ""; | |
259 | else | |
260 | result = buf; | |
261 | ||
262 | for (i = 0; i < strlen(buf); i++) | |
7283d000 | 263 | { |
5eaef520 | 264 | switch (buf[i]) |
7283d000 | 265 | { |
5eaef520 | 266 | case '"': |
267 | printf("'\"' is not allowed.\n"); | |
268 | ok = FALSE; | |
269 | break; | |
270 | case ',': | |
271 | printf("',' is not allowed.\n"); | |
272 | ok = FALSE; | |
273 | break; | |
274 | case ':': | |
275 | printf("':' is not allowed.\n"); | |
276 | ok = FALSE; | |
277 | break; | |
278 | default: | |
279 | if (iscntrl(buf[i])) | |
280 | { | |
281 | printf("Control characters are not allowed.\n"); | |
282 | ok = FALSE; | |
283 | break; | |
7283d000 | 284 | } |
285 | } | |
5eaef520 | 286 | if (!ok) |
287 | break; | |
7283d000 | 288 | } |
5eaef520 | 289 | |
290 | if (phone_num && ok) | |
291 | { | |
292 | for (i = 0; i < strlen(result); i++) | |
293 | { | |
294 | if (!isdigit(result[i]) && (result[i] != '-')) | |
295 | { | |
296 | printf("Phone numbers can contain only digits.\n"); | |
297 | ok = FALSE; | |
298 | break; | |
7283d000 | 299 | } |
5eaef520 | 300 | if (result[i] == '-') |
301 | dashes = TRUE; | |
7283d000 | 302 | } |
303 | } | |
304 | } | |
5eaef520 | 305 | |
306 | /* Remove dashes if necessary */ | |
307 | if (dashes && result == buf) | |
308 | { | |
309 | char *tmp1, *tmp2; | |
310 | tmp1 = tmp2 = (char *)buf; | |
311 | do | |
312 | { | |
313 | if (*tmp1 != '-') | |
314 | *tmp2++ = *tmp1; | |
7283d000 | 315 | } |
5eaef520 | 316 | while (*tmp1++); |
7283d000 | 317 | } |
5eaef520 | 318 | |
319 | return result; | |
7283d000 | 320 | } |
5eaef520 | 321 | |
322 | void get_new_info(struct finger_info *old_info, struct finger_info *new_info) | |
7283d000 | 323 | { |
5eaef520 | 324 | printf("Default values are printed inside of '[]'.\n"); |
325 | printf("To accept the default, type <return>.\n"); | |
326 | printf("To have a blank entry, type the word '%s'.\n\n", BLANK); | |
327 | ||
328 | #define GETINFO(m, v, n) new_info->v = strsave(ask(m, old_info->v, n)) | |
329 | ||
330 | GETINFO("Full name", fullname, FALSE); | |
331 | GETINFO("Nickname", nickname, FALSE); | |
332 | GETINFO("Home address (Ex: Atkinson 304)", home_address, FALSE); | |
333 | GETINFO("Home phone number (Ex: 3141592)", home_phone, TRUE); | |
334 | GETINFO("Office address (Exs: E40-342 or 2-108)", | |
335 | office_address, FALSE); | |
336 | GETINFO("Office phone (Ex: 3-1300)", office_phone, TRUE); | |
337 | GETINFO("MIT department (Exs: 9, Biology, Information Services)", | |
338 | mit_department, FALSE); | |
339 | GETINFO("MIT year (Exs: 1989, '91, Faculty, Grad)", mit_year, FALSE); | |
7283d000 | 340 | } |
341 | ||
5eaef520 | 342 | int usage(void) |
7283d000 | 343 | { |
5eaef520 | 344 | fprintf(stderr, "Usage: %s [user]\n", whoami); |
345 | exit(1); | |
7283d000 | 346 | } |